pybaseball / グラフの題名に対戦選手名を入れる方法を探った(藤浪投手のデータを確認しつつ)

藤浪投手のデータを確認しつつ、各選手への投球結果(何球目など)をグラフに表示。

グラフの題名に対戦選手名を入れる方法を探った

*   3試合の結果<br>
    <https://baseballsavant.mlb.com/savant-player/shintaro-fujinami-660261?stats=gamelogs-r-pitching-mlb&season=2023>

![](https://pbs.twimg.com/media/FuFVLWuacAEktho?format=jpg\&name=large)

***

# データ取得

<pre><code>!pip install pybaseball
from pybaseball import statcast
import pandas as pd
from pybaseball import statcast

dates = [
    '2023-04-01', '2023-04-08', '2023-04-15'
]

# Create an empty DataFrame to store the data
df_660261_all_dates = pd.DataFrame()

# Fetch data for each date and concatenate
for date in dates:
    df_single_day = statcast(start_dt=date, end_dt=date)
    df_660261_single_day = df_single_day[df_single_day['pitcher'] == 660261]
    df_660261_all_dates = pd.concat([df_660261_all_dates, df_660261_single_day])

# Reset the index of the final DataFrame
df_660261_all_dates.reset_index(drop=True, inplace=True)
</code></pre>

***

# 球種

<pre><code># 投球結果を抽出
df_660261 = df_660261_all_dates

# df_660261のpitch_typeカラムに含まれるユニークな球種を確認する
unique_pitch_types = df_660261['pitch_type'].unique()

# 確認した球種を表示する
print(unique_pitch_types)

</code></pre>

結果

<pre><code>['FF' 'SL' 'FS' 'ST' 'CU' 'SI']
</code></pre>

*   FF: Four-Seam Fastball - 4シームファストボール
*   SL: Slider - スライダー
*   FS: Splitter - スプリッター
*   ST: Slutter - スライダー or カッター
*   CU: Curveball - カーブ
*   SI: Sinker - シンカー (2シームファストボール)

***

# 球種カウント

<pre><code>import pandas as pd

def pitch_counts(df):
    # 左打者と右打者に対する投球データを抽出
    df_L = df[df['stand'] == 'L']
    df_R = df[df['stand'] == 'R']

    # 各カテゴリーでの球種の出現回数をカウント
    total_counts = df['pitch_type'].value_counts()
    left_counts = df_L['pitch_type'].value_counts()
    right_counts = df_R['pitch_type'].value_counts()

    # 出現回数をデータフレームにまとめる
    pitch_counts_table = pd.DataFrame({'Total': total_counts, 'Left Batter': left_counts, 'Right Batter': right_counts})

    # NaNを0に置き換える
    pitch_counts_table.fillna(0, inplace=True)

    # カウントを整数に変換する
    pitch_counts_table = pitch_counts_table.astype(int)

    return pitch_counts_table

# 続けて、球種カウントのコードを実行します。
# Split the data by date
df_0401 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_0408 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_0415 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

# Get pitch counts for each date
pitch_counts_0401 = pitch_counts(df_0401)
pitch_counts_0408 = pitch_counts(df_0408)
pitch_counts_0415 = pitch_counts(df_0415)

# Display the results
print("2023年4月1日の球種カウント:")
print(pitch_counts_0401)
print("\n2023年4月8日の球種カウント:")
print(pitch_counts_0408)
print("\n2023年4月15日の球種カウント:")
print(pitch_counts_0415)

</code></pre>

![](https://pbs.twimg.com/media/FuFWgb6aAAETIuh?format=png\&name=small)

***

# 球種カウント(円グラフ)

<pre><code>import matplotlib.pyplot as plt

def plot_pitch_distribution(df, date):
    df_L = df[df['stand'] == 'L']
    df_R = df[df['stand'] == 'R']

    fig, axs = plt.subplots(1, 3, figsize=(18, 6))
    plt.suptitle(f'Pitch Distribution on {date}')

    colors = {'FF': 'red', 'SL': 'blue', 'FS': 'green', 'ST': 'orange', 'CU': 'purple', 'SI': 'brown'}

    # Total
    df['pitch_type'].value_counts().plot(kind='pie', ax=axs[0], autopct='%.1f%%', colors=[colors[key] for key in df['pitch_type'].value_counts().index])
    axs[0].set_title('Total')
    axs[0].set_ylabel('')

    # vs Left batter
    df_L['pitch_type'].value_counts().plot(kind='pie', ax=axs[1], autopct='%.1f%%', colors=[colors[key] for key in df_L['pitch_type'].value_counts().index])
    axs[1].set_title('vs Left batter')
    axs[1].set_ylabel('')

    # vs Right batter
    df_R['pitch_type'].value_counts().plot(kind='pie', ax=axs[2], autopct='%.1f%%', colors=[colors[key] for key in df_R['pitch_type'].value_counts().index])
    axs[2].set_title('vs Right batter')
    axs[2].set_ylabel('')

    plt.show()

df_2023_04_01 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_2023_04_08 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']
plot_pitch_distribution(df_2023_04_01, '2023-04-01')
plot_pitch_distribution(df_2023_04_08, '2023-04-08')
plot_pitch_distribution(df_2023_04_15, '2023-04-15')

</code></pre>

![](https://pbs.twimg.com/media/FuFW3nJaUAI4B0m?format=jpg\&name=large)
![](https://pbs.twimg.com/media/FuFW4bLaIAAIK2f?format=jpg\&name=large)
![](https://pbs.twimg.com/media/FuFW5lRacAAPmg5?format=jpg\&name=large)

***

# 投球コース

<pre><code>import matplotlib.pyplot as plt

def plot_pitch_location(df, date):
    # データを pitch_type ごとにグループ分けする
    grouped = df.groupby('pitch_type')

    colors = {'FF': 'red', 'SL': 'blue', 'FS': 'green', 'ST': 'orange', 'CU': 'purple', 'SI': 'brown'}

    # pitch_type ごとに、'plate_x' を X 軸、'plate_z' を Y 軸とした散布図を作成する
    for pitch_type, data in grouped:
        plt.scatter(data['plate_x'], data['plate_z'], label=pitch_type, color=colors[pitch_type])

    # ストライクゾーン
    x = [-0.88, 0.88, 0.88, -0.88, -0.88]
    y = [1.51, 1.51, 3.4, 3.4, 1.51]
    plt.fill(x, y, color='r', alpha=0.3)

    # 凡例を表示する
    plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)

    plt.xlim(-3, 4)
    plt.ylim(-3, 7)

    plt.xlabel('Plate X')
    plt.ylabel('Plate Z')

    # 罫線
    plt.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    plt.title(f'Pitch Location on {date}')
    
    # グラフを表示する
    plt.show()

df_2023_04_01 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_2023_04_08 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']
plot_pitch_location(df_2023_04_01, '2023-04-01')
plot_pitch_location(df_2023_04_08, '2023-04-08')
plot_pitch_location(df_2023_04_15, '2023-04-15')

</code></pre>

![](https://pbs.twimg.com/media/FuFXS8raAAEkWh5?format=png\&name=small)
![](https://pbs.twimg.com/media/FuFXUOIaUAA2O7V?format=png\&name=small)
![](https://pbs.twimg.com/media/FuFXVSmakAE_W4p?format=png\&name=small)

***

# 投球コース(球種ごと)

<pre><code>import matplotlib.pyplot as plt

def plot_pitch_location_by_date(df_1, df_2, df_3):
    combined_df = pd.concat([df_1, df_2, df_3])
    grouped = combined_df.groupby('pitch_type')

    nrows = 3
    ncols = 2
    titles = []

    fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=(10, 15))

    for idx, (pitch_type, data) in enumerate(grouped):
        titles.append(pitch_type)

        row = idx // ncols
        col = idx % ncols

        ax = axes[row][col]

        data_1 = data[data.index.isin(df_1.index)]
        data_2 = data[data.index.isin(df_2.index)]
        data_3 = data[data.index.isin(df_3.index)]

        ax.scatter(data_1['plate_x'], data_1['plate_z'], label='2023-04-01', color='blue')
        ax.scatter(data_2['plate_x'], data_2['plate_z'], label='2023-04-08', color='red')
        ax.scatter(data_3['plate_x'], data_3['plate_z'], label='2023-04-15', color='green')

        x = [-0.88, 0.88, 0.88, -0.88, -0.88]
        y = [1.51, 1.51, 3.4, 3.4, 1.51]
        ax.fill(x, y, color='r', alpha=0.3)

        ax.set_title(pitch_type)
        ax.set_xlabel('Plate X')
        ax.set_ylabel('Plate Z')

        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)
        ax.legend()

        ax.set_xlim(-3, 4)  # X軸の最小値と最大値を設定
        ax.set_ylim(-3, 7)  # Y軸の最小値と最大値を設定

    plt.tight_layout()
    plt.show()

df_2023_04_01 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_2023_04_08 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

plot_pitch_location_by_date(df_2023_04_01, df_2023_04_08, df_2023_04_15)

</code></pre>

![](https://pbs.twimg.com/media/FuFX0XXaEAEa6X3?format=png\&name=large)

***

# リリースポイント

<pre><code>import matplotlib.pyplot as plt

def plot_release_point(df, date):
    grouped = df.groupby('pitch_type')

    colors = {'FF': 'blue', 'SL': 'red', 'FS': 'green', 'ST': 'orange', 'CU': 'purple', 'SI': 'brown'}

    for pitch_type, data in grouped:
        plt.scatter(data['release_pos_x'], data['release_pos_z'], label=pitch_type, color=colors[pitch_type])

    plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0)

    plt.xlabel('Release Pos X')
    plt.ylabel('Release Pos Z')

    plt.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    plt.title(f'Release Point for {date}')

    plt.xlim(-3, -1)
    plt.ylim(4.5, 6.5)

    plt.show()

df_2023_04_01 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_2023_04_08 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

plot_release_point(df_2023_04_01, '2023-04-01')
plot_release_point(df_2023_04_08, '2023-04-08')
plot_release_point(df_2023_04_15, '2023-04-15')

</code></pre>

![](https://pbs.twimg.com/media/FuFYE5IaEAIVpAD?format=png\&name=small)
![](https://pbs.twimg.com/media/FuFYGOFaUAIOgiI?format=png\&name=small)
![](https://pbs.twimg.com/media/FuFYHZgaYAAo19b?format=png\&name=small)

***

# リリースポイント(球種ごと)

<pre><code>import matplotlib.pyplot as plt

def plot_release_point_by_date(df_1, df_2, df_3):
    combined_df = pd.concat([df_1, df_2, df_3])

    grouped = combined_df.groupby('pitch_type')

    nrows = 3
    ncols = 2

    titles = []

    fig, axes = plt.subplots(nrows=nrows, ncols=ncols, figsize=(10, 15))

    for idx, (pitch_type, data) in enumerate(grouped):
        titles.append(pitch_type)

        row = idx // ncols
        col = idx % ncols

        ax = axes[row][col]

        data_1 = data[data.index.isin(df_1.index)]
        data_2 = data[data.index.isin(df_2.index)]
        data_3 = data[data.index.isin(df_3.index)]

        ax.scatter(data_1['release_pos_x'], data_1['release_pos_z'], label='2023-04-01', color='blue')
        ax.scatter(data_2['release_pos_x'], data_2['release_pos_z'], label='2023-04-08', color='red')
        ax.scatter(data_3['release_pos_x'], data_3['release_pos_z'], label='2023-04-15', color='green')

        ax.set_title(pitch_type)
        ax.set_xlabel('Release Pos X')
        ax.set_ylabel('Release Pos Z')

        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

        ax.legend()

        # Set the limits for X and Y axes
        ax.set_xlim(-3, -1)
        ax.set_ylim(4.5, 6.5)

    plt.tight_layout()
    plt.show()

df_2023_04_01 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-01']
df_2023_04_08 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-08']
df_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

plot_release_point_by_date(df_2023_04_01, df_2023_04_08, df_2023_04_15)

</code></pre>

![](https://pbs.twimg.com/media/FuFYksQakAMyBgZ?format=png\&name=large)

***

# スピンレート(球種ごと) / Boxplot

<pre><code>import matplotlib.pyplot as plt
import pandas as pd

def plot_spin_rate_by_date_boxplot(df_1, df_2, df_3, pitch_types, dates):
    pitch_types = [pt for pt in pitch_types if pt is not None and pd.notna(pt)]  # nan を除外
    fig, axs = plt.subplots(len(pitch_types), 1, figsize=(8, len(pitch_types) * 4))

    for i, pitch_type in enumerate(pitch_types):
        ax = axs[i]

        grouped_1 = df_1[df_1['pitch_type'] == pitch_type].dropna(subset=['release_spin_rate'])
        grouped_2 = df_2[df_2['pitch_type'] == pitch_type].dropna(subset=['release_spin_rate'])
        grouped_3 = df_3[df_3['pitch_type'] == pitch_type].dropna(subset=['release_spin_rate'])

        data_to_plot = []
        labels = []
        if not grouped_1.empty:
            data_to_plot.append(grouped_1['release_spin_rate'])
            labels.append(dates[0])
        if not grouped_2.empty:
            data_to_plot.append(grouped_2['release_spin_rate'])
            labels.append(dates[1])
        if not grouped_3.empty:
            data_to_plot.append(grouped_3['release_spin_rate'])
            labels.append(dates[2])

        if data_to_plot:
            bp = ax.boxplot(data_to_plot, labels=labels)
            for j, d in enumerate(data_to_plot):
                mean_val = d.mean()
                ax.text(j + 0.8, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')

        ax.set_title(f"Pitch Type: {pitch_type}")
        ax.set_xlabel('Date')
        ax.set_ylabel('Release Spin Rate')

        # 罫線
        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    fig.suptitle('Release Spin Rate by Date and Pitch Type', fontsize=16, y=1.02)
    plt.tight_layout(pad=3)
    plt.show()

pitch_types_1 = df_2023_04_01['pitch_type'].unique()
pitch_types_2 = df_2023_04_08['pitch_type'].unique()
pitch_types_3 = df_2023_04_15['pitch_type'].unique()

# すべての日に存在する球種を取得
all_pitch_types = set(pitch_types_1) | set(pitch_types_2) | set(pitch_types_3)
dates = ["2023-04-01", "2023-04-08", "2023-04-15"]


plot_spin_rate_by_date_boxplot(df_2023_04_01, df_2023_04_08, df_2023_04_15, all_pitch_types, dates)

</code></pre>

![](https://pbs.twimg.com/media/FuFY1SDaEAMkD92?format=png\&name=large)

***

# スピード(球種ごと) / Boxplot

<pre><code>def plot_release_speed_by_date_boxplot(df_1, df_2, df_3, pitch_types, dates):
    pitch_types = [pt for pt in pitch_types if pt is not None and pd.notna(pt)]  # nan を除外
    fig, axs = plt.subplots(len(pitch_types), 1, figsize=(8, len(pitch_types) * 4))

    for i, pitch_type in enumerate(pitch_types):
        ax = axs[i]

        grouped_1 = df_1[df_1['pitch_type'] == pitch_type].dropna(subset=['release_speed'])
        grouped_2 = df_2[df_2['pitch_type'] == pitch_type].dropna(subset=['release_speed'])
        grouped_3 = df_3[df_3['pitch_type'] == pitch_type].dropna(subset=['release_speed'])

        data_to_plot = []
        labels = []
        if not grouped_1.empty:
            data_to_plot.append(grouped_1['release_speed'])
            labels.append(dates[0])
        if not grouped_2.empty:
            data_to_plot.append(grouped_2['release_speed'])
            labels.append(dates[1])
        if not grouped_3.empty:
            data_to_plot.append(grouped_3['release_speed'])
            labels.append(dates[2])

        if data_to_plot:
            bp = ax.boxplot(data_to_plot, labels=labels)
            for j, d in enumerate(data_to_plot):
                mean_val = d.mean()
                ax.text(j + 0.8, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')

        ax.set_title(f"Pitch Type: {pitch_type}")
        ax.set_xlabel('Date')
        ax.set_ylabel('Release Speed')

        # 罫線
        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    fig.suptitle('Release Speed by Date and Pitch Type', fontsize=16, y=1.02)
    plt.tight_layout(pad=3)
    plt.show()

# 2023年4月1日、4月8日、4月15日のデータに対してリリーススピードをプロット
dates = ['2023-04-01', '2023-04-08', '2023-04-15']
plot_release_speed_by_date_boxplot(df_2023_04_01, df_2023_04_08, df_2023_04_15, all_pitch_types, dates)

</code></pre>

![](https://pbs.twimg.com/media/FuFZSM8aMAEEmpi?format=png\&name=4096x4096)

***

# スピード(球種ごと) / Boxplot　※kmへ換算

<pre><code>def plot_release_speed_by_date_boxplot_km(df_1, df_2, df_3, pitch_types, dates):
    pitch_types = [pt for pt in pitch_types if pt is not None and pd.notna(pt)]  # nan を除外
    fig, axs = plt.subplots(len(pitch_types), 1, figsize=(8, len(pitch_types) * 4))

    for i, pitch_type in enumerate(pitch_types):
        ax = axs[i]

        grouped_1 = df_1[df_1['pitch_type'] == pitch_type].dropna(subset=['release_speed'])
        grouped_2 = df_2[df_2['pitch_type'] == pitch_type].dropna(subset=['release_speed'])
        grouped_3 = df_3[df_3['pitch_type'] == pitch_type].dropna(subset=['release_speed'])

        data_to_plot = []
        labels = []
        if not grouped_1.empty:
            data_to_plot.append(grouped_1['release_speed'] * 1.60934)
            labels.append(dates[0])
        if not grouped_2.empty:
            data_to_plot.append(grouped_2['release_speed'] * 1.60934)
            labels.append(dates[1])
        if not grouped_3.empty:
            data_to_plot.append(grouped_3['release_speed'] * 1.60934)
            labels.append(dates[2])

        if data_to_plot:
            bp = ax.boxplot(data_to_plot, labels=labels)
            for j, d in enumerate(data_to_plot):
                mean_val = d.mean()
                ax.text(j + 0.8, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')

        ax.set_title(f"Pitch Type: {pitch_type}")
        ax.set_xlabel('Date')
        ax.set_ylabel('Release Speed (km/h)')

        # 罫線
        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    fig.suptitle('Release Speed by Date and Pitch Type (km/h)', fontsize=16, y=1.02)
    plt.tight_layout(pad=3)
    plt.show()

# 2023年4月1日、4月8日、4月15日のデータに対してリリーススピードをキロメートル単位でプロット
dates = ['2023-04-01', '2023-04-08', '2023-04-15']
plot_release_speed_by_date_boxplot_km(df_2023_04_01, df_2023_04_08, df_2023_04_15, all_pitch_types, dates)

</code></pre>

![](https://pbs.twimg.com/media/FuFZnK6aYAQPolk?format=png\&name=large)

***

# リリースポイント ～ ホーム距離 (球種ごと) / Boxplot

<pre><code>def plot_release_extension_by_date_boxplot(df_1, df_2, df_3, pitch_types, dates):
    pitch_types = [pt for pt in pitch_types if pt is not None and pd.notna(pt)]  # nan を除外
    fig, axs = plt.subplots(len(pitch_types), 1, figsize=(8, len(pitch_types) * 4))

    for i, pitch_type in enumerate(pitch_types):
        ax = axs[i]

        grouped_1 = df_1[df_1['pitch_type'] == pitch_type].dropna(subset=['release_extension'])
        grouped_2 = df_2[df_2['pitch_type'] == pitch_type].dropna(subset=['release_extension'])
        grouped_3 = df_3[df_3['pitch_type'] == pitch_type].dropna(subset=['release_extension'])

        data_to_plot = []
        labels = []
        if not grouped_1.empty:
            data_to_plot.append(grouped_1['release_extension'])
            labels.append(dates[0])
        if not grouped_2.empty:
            data_to_plot.append(grouped_2['release_extension'])
            labels.append(dates[1])
        if not grouped_3.empty:
            data_to_plot.append(grouped_3['release_extension'])
            labels.append(dates[2])

        if data_to_plot:
            bp = ax.boxplot(data_to_plot, labels=labels)
            for j, d in enumerate(data_to_plot):
                mean_val = d.mean()
                ax.text(j + 0.8, mean_val, f"{mean_val:.1f}", ha='center', va='bottom', fontsize=10, color='blue')

        ax.set_title(f"Pitch Type: {pitch_type}")
        ax.set_xlabel('Date')
        ax.set_ylabel('Release Extension (ft)')

        # 罫線
        ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

    fig.suptitle('Release Extension by Date and Pitch Type (ft)', fontsize=16, y=1.02)
    plt.tight_layout(pad=3)
    plt.show()

# 2023年4月1日、4月8日、4月15日のデータに対してリリースエクステンションをプロット
dates = ['2023-04-01', '2023-04-08', '2023-04-15']
plot_release_extension_by_date_boxplot(df_2023_04_01, df_2023_04_08, df_2023_04_15, all_pitch_types, dates)

</code></pre>

![](https://pbs.twimg.com/media/FuFaAetagAo7ue1?format=png\&name=4096x4096)

***

# 対戦打者・結果

<pre><code># 2023年4月15日のデータをフィルタリング
df_660261_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

# 必要な列を選択
df_660261_2023_04_15_results = df_660261_2023_04_15[['batter', 'events', 'des']]

# 2023年4月15日のデータをフィルタリング
df_660261_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

# events列がNaNでない行をフィルタリング
df_660261_2023_04_15_results_filtered = df_660261_2023_04_15_results.dropna(subset=['events'])

# 結果を表示
print(df_660261_2023_04_15_results_filtered)


</code></pre>

結果

<pre><code>     batter        events                                                des
134  596129          walk                            Daniel Vogelbach walks.
140  592192      home_run  Mark Canha homers (2) on a fly ball to left fi...
144  643446     field_out  Jeff McNeil grounds out, first baseman Jesus A...
147  624413     field_out  Pete Alonso grounds out, shortstop Aledmys Dia...
148  596019     field_out  Francisco Lindor grounds out, second baseman T...
154  516782  hit_by_pitch                       Starling Marte hit by pitch.
156  607043     field_out  Brandon Nimmo lines out sharply to right field...
159  682626     strikeout       Francisco Alvarez strikes out on a foul tip.
164  641645          walk                              Luis Guillorme walks.
168  596129     field_out  Daniel Vogelbach grounds out, third baseman Ja...
172  592192     field_out  Mark Canha flies out sharply to center fielder...
175  643446     field_out  Jeff McNeil grounds out to first baseman Jesus...
178  624413      home_run  Pete Alonso homers (7) on a fly ball to left f...
180  596019     field_out  Francisco Lindor grounds out, second baseman T...
186  516782     field_out  Starling Marte flies out sharply to center fie...
190  607043        single  Brandon Nimmo singles on a line drive to right...
195  682626     field_out  Francisco Alvarez flies out to second baseman ...
196  641645     strikeout               Luis Guillorme strikes out swinging.
201  596129     field_out  Daniel Vogelbach grounds out, first baseman Je...
204  592192     strikeout                   Mark Canha strikes out swinging.
209  643446     field_out  Jeff McNeil flies out to center fielder Esteur...
211  624413     strikeout                  Pete Alonso strikes out swinging.
214  596019        double  Francisco Lindor doubles (6) on a ground ball ...
218  516782     field_out  Starling Marte flies out to left fielder Conne...
220  607043     strikeout                Brandon Nimmo strikes out swinging.
</code></pre>

***

# 対戦打者・結果(並び替え)

<pre><code># 2023年4月15日のデータをフィルタリング
df_660261_2023_04_15 = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

# 必要な列を選択
df_660261_2023_04_15_results = df_660261_2023_04_15[['batter', 'events', 'des', 'at_bat_number']]

# events列がNaNでない行をフィルタリング
df_660261_2023_04_15_results_filtered = df_660261_2023_04_15_results.dropna(subset=['events'])

# at_bat_number 列を使って df_660261_2023_04_15_results_filtered をソート
df_660261_2023_04_15_results_filtered_sorted = df_660261_2023_04_15_results_filtered.sort_values(by='at_bat_number')

# 結果を表示
print(df_660261_2023_04_15_results_filtered_sorted)
</code></pre>

結果

<pre><code>     batter        events                                                des  \
220  607043     strikeout                Brandon Nimmo strikes out swinging.   
218  516782     field_out  Starling Marte flies out to left fielder Conne...   
214  596019        double  Francisco Lindor doubles (6) on a ground ball ...   
211  624413     strikeout                  Pete Alonso strikes out swinging.   
209  643446     field_out  Jeff McNeil flies out to center fielder Esteur...   
204  592192     strikeout                   Mark Canha strikes out swinging.   
201  596129     field_out  Daniel Vogelbach grounds out, first baseman Je...   
196  641645     strikeout               Luis Guillorme strikes out swinging.   
195  682626     field_out  Francisco Alvarez flies out to second baseman ...   
190  607043        single  Brandon Nimmo singles on a line drive to right...   
186  516782     field_out  Starling Marte flies out sharply to center fie...   
180  596019     field_out  Francisco Lindor grounds out, second baseman T...   
178  624413      home_run  Pete Alonso homers (7) on a fly ball to left f...   
175  643446     field_out  Jeff McNeil grounds out to first baseman Jesus...   
172  592192     field_out  Mark Canha flies out sharply to center fielder...   
168  596129     field_out  Daniel Vogelbach grounds out, third baseman Ja...   
164  641645          walk                              Luis Guillorme walks.   
159  682626     strikeout       Francisco Alvarez strikes out on a foul tip.   
156  607043     field_out  Brandon Nimmo lines out sharply to right field...   
154  516782  hit_by_pitch                       Starling Marte hit by pitch.   
148  596019     field_out  Francisco Lindor grounds out, second baseman T...   
147  624413     field_out  Pete Alonso grounds out, shortstop Aledmys Dia...   
144  643446     field_out  Jeff McNeil grounds out, first baseman Jesus A...   
140  592192      home_run  Mark Canha homers (2) on a fly ball to left fi...   
134  596129          walk                            Daniel Vogelbach walks.  
</code></pre>

![](https://pbs.twimg.com/media/FuFbC2qaUAQJNEt?format=png\&name=small)

***

# 各打者との対戦結果

<pre><code>import matplotlib.pyplot as plt

# 2023年4月15日のデータをフィルタリング
df_660261_fujinami = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

unique_batters = sorted(df_660261_fujinami['at_bat_number'].unique())
nrows = (len(unique_batters) + 1) // 2
ncols = 2
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)

x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]

# at_bat_number でグループ化
grouped_by_batter = df_660261_fujinami.groupby('at_bat_number')

# グラフのタイトル用に結果データを取得
results_data = df_660261_2023_04_15_results_filtered_sorted

# unique_batters を at_bat_number で並べ替え
unique_batters = sorted(unique_batters, key=lambda x: grouped_by_batter.get_group(x).iloc[0]['at_bat_number'])

for i, batter in enumerate(unique_batters):
    data_by_batter = grouped_by_batter.get_group(batter)
    ax = axs[i // ncols, i % ncols]
    
    ax.fill(x, y, color='r', alpha=0.1)

    grouped_by_pitch_type = data_by_batter.groupby('pitch_type')
    
    for pitch_type, data in grouped_by_pitch_type:
        ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type, s=200)
        
        hit_data = data[data['events'].isin(['single', 'double', 'triple', 'home_run'])]
        if not hit_data.empty:
            ax.scatter(hit_data['plate_x'], hit_data['plate_z'], marker='x', s=100, label=f'Hit ({pitch_type})')

        for idx, row in data.iterrows():
            ax.text(row['plate_x'], row['plate_z'], f"{row['pitch_number']}", fontsize=12, ha='center', va='center', color='white')

    last_pitch_result = results_data.iloc[i]['events']
    
    ax.set_title(f'Batter {i+1} (Last Pitch: {last_pitch_result})')
    
    ax.set_xlim(-3, 3)
    ax.set_ylim(-2, 6)
    ax.set_xlabel('Plate X')
    ax.set_ylabel('Plate Z')
    ax.legend()
    ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

plt.tight_layout()
plt.show()
</code></pre>

![](https://pbs.twimg.com/media/FuFbZjqacAEee-1?format=jpg\&name=4096x4096)

***

# 各打者との対戦結果(題名に対戦ID)

<pre><code>import matplotlib.pyplot as plt

# 2023年4月15日のデータをフィルタリング
df_660261_fujinami = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

unique_batters = sorted(df_660261_fujinami['at_bat_number'].unique())
nrows = (len(unique_batters) + 1) // 2
ncols = 2
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)

x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]

# at_bat_number でグループ化
grouped_by_batter = df_660261_fujinami.groupby('at_bat_number')

# グラフのタイトル用に結果データを取得
results_data = df_660261_2023_04_15_results_filtered_sorted[['batter', 'events', 'des']]

# unique_batters を at_bat_number で並べ替え
unique_batters = sorted(unique_batters, key=lambda x: grouped_by_batter.get_group(x).iloc[0]['at_bat_number'])

for i, batter in enumerate(unique_batters):
    data_by_batter = grouped_by_batter.get_group(batter)
    ax = axs[i // ncols, i % ncols]
    
    ax.fill(x, y, color='r', alpha=0.1)

    grouped_by_pitch_type = data_by_batter.groupby('pitch_type')
    
    for pitch_type, data in grouped_by_pitch_type:
        ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type, s=200)
        
        hit_data = data[data['events'].isin(['single', 'double', 'triple', 'home_run'])]
        if not hit_data.empty:
            ax.scatter(hit_data['plate_x'], hit_data['plate_z'], marker='x', s=100, label=f'Hit ({pitch_type})')

        for idx, row in data.iterrows():
            ax.text(row['plate_x'], row['plate_z'], f"{row['pitch_number']}", fontsize=12, ha='center', va='center', color='white')
            
            last_pitch_result = results_data.iloc[i]['events']

    # タイトルに表示する打者IDを取得
    batter_id = results_data.iloc[i]['batter']

    # イニングとアウトカウントを取得
    inning = data_by_batter.iloc[0]['inning']
    outs_when_up = data_by_batter.iloc[0]['outs_when_up']

    # タイトルを設定
    ax.set_title(f'Batter {batter_id}: Inning {inning}, Outs {outs_when_up} - {last_pitch_result}')

    ax.set_xlim(-3, 3)
    ax.set_ylim(-2, 6)
    ax.set_xlabel('Plate X')
    ax.set_ylabel('Plate Z')
    ax.legend()
    ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

plt.tight_layout()
plt.show()


</code></pre>

![](https://pbs.twimg.com/media/FuFbt7haUAELH\_-?format=jpg\&name=4096x4096)

***

# 各打者との対戦結果 / 文章

<pre><code>des_list = df_660261_2023_04_15_results_filtered_sorted['des'].tolist()

for des in des_list:
    print(des)

</code></pre>

結果

<pre><code>Brandon Nimmo strikes out swinging.
Starling Marte flies out to left fielder Conner Capel.
Francisco Lindor doubles (6) on a ground ball to right fielder Ramon Laureano.
Pete Alonso strikes out swinging.
Jeff McNeil flies out to center fielder Esteury Ruiz.
Mark Canha strikes out swinging.
Daniel Vogelbach grounds out, first baseman Jesus Aguilar to pitcher Shintaro Fujinami.
Luis Guillorme strikes out swinging.
Francisco Alvarez flies out to second baseman Tony Kemp.
Brandon Nimmo singles on a line drive to right fielder Ramon Laureano.
Starling Marte flies out sharply to center fielder Esteury Ruiz.
Francisco Lindor grounds out, second baseman Tony Kemp to first baseman Jesus Aguilar.
Pete Alonso homers (7) on a fly ball to left field.
Jeff McNeil grounds out to first baseman Jesus Aguilar.
Mark Canha flies out sharply to center fielder Esteury Ruiz.
Daniel Vogelbach grounds out, third baseman Jace Peterson to first baseman Jesus Aguilar.
Luis Guillorme walks.
Francisco Alvarez strikes out on a foul tip.
Brandon Nimmo lines out sharply to right fielder Ramon Laureano.
Starling Marte hit by pitch.
Francisco Lindor grounds out, second baseman Tony Kemp to first baseman Jesus Aguilar.   Starling Marte to 3rd.
Pete Alonso grounds out, shortstop Aledmys Diaz to first baseman Jesus Aguilar.
Jeff McNeil grounds out, first baseman Jesus Aguilar to pitcher Shintaro Fujinami.
Mark Canha homers (2) on a fly ball to left field.
Daniel Vogelbach walks.
</code></pre>

***

# 各打者との対戦結果 / 文章　※並び替え

<pre><code>des_list = df_660261_2023_04_15_results_filtered_sorted['des'].tolist()

for i, des in enumerate(des_list, 1):
    print(f"{i}. {des}")

</code></pre>

結果

<pre><code>1. Brandon Nimmo strikes out swinging.
2. Starling Marte flies out to left fielder Conner Capel.
3. Francisco Lindor doubles (6) on a ground ball to right fielder Ramon Laureano.
4. Pete Alonso strikes out swinging.
5. Jeff McNeil flies out to center fielder Esteury Ruiz.
6. Mark Canha strikes out swinging.
7. Daniel Vogelbach grounds out, first baseman Jesus Aguilar to pitcher Shintaro Fujinami.
8. Luis Guillorme strikes out swinging.
9. Francisco Alvarez flies out to second baseman Tony Kemp.
10. Brandon Nimmo singles on a line drive to right fielder Ramon Laureano.
11. Starling Marte flies out sharply to center fielder Esteury Ruiz.
12. Francisco Lindor grounds out, second baseman Tony Kemp to first baseman Jesus Aguilar.
13. Pete Alonso homers (7) on a fly ball to left field.
14. Jeff McNeil grounds out to first baseman Jesus Aguilar.
15. Mark Canha flies out sharply to center fielder Esteury Ruiz.
16. Daniel Vogelbach grounds out, third baseman Jace Peterson to first baseman Jesus Aguilar.
17. Luis Guillorme walks.
18. Francisco Alvarez strikes out on a foul tip.
19. Brandon Nimmo lines out sharply to right fielder Ramon Laureano.
20. Starling Marte hit by pitch.
21. Francisco Lindor grounds out, second baseman Tony Kemp to first baseman Jesus Aguilar.   Starling Marte to 3rd.
22. Pete Alonso grounds out, shortstop Aledmys Diaz to first baseman Jesus Aguilar.
23. Jeff McNeil grounds out, first baseman Jesus Aguilar to pitcher Shintaro Fujinami.
24. Mark Canha homers (2) on a fly ball to left field.
25. Daniel Vogelbach walks.
</code></pre>

1.  ブランドン・ニモが空振り三振。
2.  スターリング・マルテが左翼手コナー・ケーペルへのフライアウト。
3.  フランシスコ・リンドーアがライトフィールダー・ラモン・ローレアノへのグラウンドボールで二塁打（6）。
4.  ピート・アロンソが空振り三振。
5.  ジェフ・マクニールが中堅手エステュリ・ルイスへのフライアウト。
6.  マーク・カナが空振り三振。
7.  ダニエル・ヴォーゲルバックが一塁手ジーザス・アギラーから投手藤浪晋太郎へのゴロアウト。
8.  ルイス・ギリオルメが空振り三振。
9.  フランシスコ・アルバレスが二塁手トニー・ケンプへのフライアウト。
10. ブランドン・ニモがライトフィールダー・ラモン・ローレアノへのライナーシングル。
11. スターリング・マルテが中堅手エステュリ・ルイスへの鋭いフライアウト。
12. フランシスコ・リンドーアが二塁手トニー・ケンプから一塁手ジーザス・アギラーへのゴロアウト。
13. ピート・アロンソが左翼への本塁打（7）。
14. ジェフ・マクニールが一塁手ジーザス・アギラーへのゴロアウト。
15. マーク・カナが中堅手エステュリ・ルイスへの鋭いフライアウト。
16. ダニエル・ヴォーゲルバックが三塁手ジェイス・ピーターソンから一塁手ジーザス・アギラーへのゴロアウト。
17. ルイス・ギリオルメが四球。
18. フランシスコ・アルバレスがファウルチップで三振。
19. ブランドン・ニモがライトフィールダー・ラモン・ローレアノへの鋭いライナーアウト。
20. スターリング・マルテが死球。
21. フランシスコ・リンドーアが二塁手トニー・ケンプから一塁手ジーザス・アギラーへのゴロアウト。スターリング・マルテが3塁へ進む。
22. ピート・アロンソが遊撃手アレドミス・ディアスから一塁手ジーザス・アギラーへのゴロアウト。
23. ジェフ・マクニールが一塁手ジーザス・アギラーから投手藤浪晋太郎へのゴロアウト。
24. マーク・カナが左翼への本塁打（2）。
25. ダニエル・ヴォーゲルバックが四球。

***

# 対戦打者ID

<pre><code># 2023年4月15日のデータをフィルタリング
df_660261_fujinami = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

unique_batters = sorted(df_660261_fujinami['at_bat_number'].unique())

# at_bat_number でグループ化
grouped_by_batter = df_660261_fujinami.groupby('at_bat_number')

# グラフのタイトル用に結果データを取得
results_data = df_660261_2023_04_15_results_filtered_sorted[['batter', 'events', 'des']]

# unique_batters を at_bat_number で並べ替え
unique_batters = sorted(unique_batters, key=lambda x: grouped_by_batter.get_group(x).iloc[0]['at_bat_number'])

# バッターIDを格納するリスト
batter_ids = []

# 各バッターのIDをリストに追加
for i, batter in enumerate(unique_batters):
    batter_id = results_data.iloc[i]['batter']
    batter_ids.append(batter_id)

print(batter_ids)

</code></pre>

結果

<pre><code>[607043, 516782, 596019, 624413, 643446, 592192, 596129, 641645, 682626, 607043, 516782, 596019, 624413, 643446, 592192, 596129, 641645, 682626, 607043, 516782, 596019, 624413, 643446, 592192, 596129]
</code></pre>

***

# 対戦打者ID - 名前の紐づけ

<pre><code>from pybaseball import playerid_reverse_lookup

# バッターIDのリスト
batter_ids = [607043, 516782, 596019, 624413, 643446, 592192, 596129, 641645, 682626, 607043, 516782, 596019, 624413, 643446, 592192, 596129, 641645, 682626, 607043, 516782, 596019, 624413, 643446, 592192, 596129]

# 重複を削除する
unique_batter_ids = list(set(batter_ids))

# バッターIDと名前の対応関係を格納する辞書
batter_names = {}

# IDごとに選手名を検索
for batter_id in unique_batter_ids:
    player_info = playerid_reverse_lookup([batter_id], key_type='mlbam')
    batter_name = player_info['name_first'].iloc[0] + ' ' + player_info['name_last'].iloc[0]
    batter_names[batter_id] = batter_name

# バッターIDと名前の対応関係を表示
for batter_id, batter_name in batter_names.items():
    print(f'{batter_id}: {batter_name}')

</code></pre>

結果

<pre><code>Gathering player lookup table. This may take a moment.
592192: mark canha
596129: dan vogelbach
682626: francisco álvarez
607043: brandon nimmo
641645: luis guillorme
516782: starling marte
596019: francisco lindor
643446: jeff mcneil
624413: pete alonso
</code></pre>

***

# 各対戦打者との結果 (題名に名前入り)

<pre><code>import matplotlib.pyplot as plt

# ID と選手名のマッピング
id_to_name_mapping = {
    592192: "Mark Canha",
    596129: "Dan Vogelbach",
    682626: "Francisco Álvarez",
    607043: "Brandon Nimmo",
    641645: "Luis Guillorme",
    516782: "Starling Marte",
    596019: "Francisco Lindor",
    643446: "Jeff McNeil",
    624413: "Pete Alonso"
}

# 2023年4月15日のデータをフィルタリング
df_660261_fujinami = df_660261_all_dates[df_660261_all_dates['game_date'] == '2023-04-15']

unique_batters = sorted(df_660261_fujinami['at_bat_number'].unique())
nrows = (len(unique_batters) + 1) // 2
ncols = 2
fig, axs = plt.subplots(nrows, ncols, figsize=(12, nrows * 6), sharex=True, sharey=True)

x = [-0.88, 0.88, 0.88, -0.88, -0.88]
y = [1.51, 1.51, 3.4, 3.4, 1.51]

# at_bat_number でグループ化
grouped_by_batter = df_660261_fujinami.groupby('at_bat_number')

# グラフのタイトル用に結果データを取得
results_data = df_660261_2023_04_15_results_filtered_sorted[['batter', 'events', 'des']]

# unique_batters を at_bat_number で並べ替え
unique_batters = sorted(unique_batters, key=lambda x: grouped_by_batter.get_group(x).iloc[0]['at_bat_number'])

for i, batter in enumerate(unique_batters):
    data_by_batter = grouped_by_batter.get_group(batter)
    ax = axs[i // ncols, i % ncols]
    
    ax.fill(x, y, color='r', alpha=0.1)

    grouped_by_pitch_type = data_by_batter.groupby('pitch_type')
    
    for pitch_type, data in grouped_by_pitch_type:
        ax.scatter(data['plate_x'], data['plate_z'], label=pitch_type, s=200)
        
        hit_data = data[data['events'].isin(['single', 'double', 'triple', 'home_run'])]
        if not hit_data.empty:
            ax.scatter(hit_data['plate_x'], hit_data['plate_z'], marker='x', s=100, label=f'Hit ({pitch_type})')

        for idx, row in data.iterrows():
            ax.text(row['plate_x'], row['plate_z'], f"{row['pitch_number']}", fontsize=12, ha='center', va='center', color='white')
            
            last_pitch_result = results_data.iloc[i]['events']

    # タイトルに表示する打者名を取得
    batter_id = results_data.iloc[i]['batter']
    batter_name = id_to_name_mapping[batter_id]

    # イニングとアウトカウントを取得
    inning = data_by_batter.iloc[0]['inning']
    outs_when_up = data_by_batter.iloc[0]['outs_when_up']

    # タイトルを設定
    ax.set_title(f'{batter_name} : Inning {inning}, Outs {outs_when_up} - {last_pitch_result}')
    
    ax.set_xlim(-3, 3)
    ax.set_ylim(-2, 6)
    ax.set_xlabel('Plate X')
    ax.set_ylabel('Plate Z')
    ax.legend()
    ax.grid(which='both', linestyle='--', color='gray', alpha=0.5)

plt.tight_layout()
plt.show()
</code></pre>

![](https://pbs.twimg.com/media/FuFdO0OaMAEo0Ny?format=jpg\&name=4096x4096)

***

以上