Pythonで作成した円グラフ(山本由伸の投球分析)に色を指定する【Matplotlib】

Pythonで作成した円グラフ(山本由伸の投球分析)に色を指定する【Matplotlib】 プログラミング

Pythonでグラフを作成する場合に問題が発生しました。
その問題とは、色に関することです。

早速ですが、以下のグラフを見てください。

オリックス山本由伸の全投球分析

内容は、オリックス山本由伸投手の投球に関する分析結果です。
違和感を感じませんか?

全投球のストレートは、青色です。
それに対して、決め球のストレートはオレンジ色となります。
なお、決め球のフォークが青色となっています。

この配色は、とてもわかりずらくないでしょうか?
ストレートは、青色で統一して欲しいと思いませんか?

思いますよね。
この記事では、この色バラバラ問題を解決する方法を説明していきます。

本記事の内容

  • 解決方法は辞書型の永続データを用意すること
  • 辞書型データの作成
  • 辞書型データの保存(永続化)
  • 辞書型データから色リストの作成
  • 色を統一した円グラフ

それでは、上記に沿って解説していきます。

解決方法は辞書型の永続データを用意すること

結論は、辞書型の永続データを用意することです。

Pythonでは辞書型は、よく出てくるデータ型ですね。
もし理解が曖昧な場合は、次の記事で内容を確認してください。

永続データとは、簡単に言えば保存するデータと言う事ですね。
外部ファイルやデータベースに保存するのが、一般的でしょう。

もちろん、定数という形でコードにべた書きでも問題はありません。
でも、今回はそれを取り上げません。
べた書きは、スキル的には何も広がりませんからね。

以上より、解決方法の方向性については決まりました。
ここから先では、具体的な方法を示しながら問題解決に取り組んでいきます。

辞書型データの作成

具体例とともに辞書型データを説明していきます。
ただ、その前に対象とするデータと分析内容に関して説明しておきます。

対象データ

2020年プロ野球におけるピッチャーの全投球を対象としています。
期間は、2020年06月19日~2020年10月10日となります。

全投球数は、173373球。
MongoDBに173373件のレコードを登録している状態です。

レコードは、以下のような形式となります。

{
    "_id" : ObjectId("5f81e24e465c99e3d94e6add"),
    "game_id" : "2020101006",
    "ball_count" : "1",
    "ball_no" : "1",
    "ball_type" : "ストレート",
    "batter_id" : "1800050",
    "batter_name" : "藤原 恭大",
    "catcher_id" : "1200096",
    "catcher_name" : "田村 龍弘",
    "pitcher_id" : "1800107",
    "pitcher_name" : "杉山 一樹",
    "result" : "空振り",
    "speed" : "154",
    "x" : "64",
    "y" : "54"
},

分析内容

冒頭に挙げた円グラフが、分析内容となります。
簡単に言うと、投手ごとの決め球を調査しています。

山本由伸投手の場合であれば、フォークが決め球だと明らかです。
また、普段からフォークが多いということもわかります。
このような分析をするために、全投球と決め球の円グラフを並べています。

そこで、今回の色バラバラ問題がクローズアップされたと言うことです。
そして、今回は球種がグラフを構成する要素になりますね。

球種ごとに色を指定する(辞書型データの対象)

やっと、本題です。
イメージはできましたか?

球種ごとに色(カラーコード)が関連付いていれば、OKと言えます。
その関連付けを辞書型データで行おうと言うことです。

そのためには、まずは全球種の洗い出しから行います。
合計は、16種(173373球)です。

ball_typecount
ストレート74714
スライダー27944
カットボール14157
フォーク13470
ツーシーム10602
チェンジアップ10350
カーブ8767
シュート4555
ナックルカーブ2508
シンカー2318
スプリット2003
縦スライダー1266
パワーカーブ412
スローカーブ111
スクリュー102
スラーブ94

球種(ball_type)をキーにした辞書型データを作成します。
作成した辞書型データは以下。

{'ストレート': (0.12156862745098039, 0.4666666666666667, 0.7058823529411765), 'スライダー': (0.6823529411764706, 0.7803921568627451, 0.9098039215686274), 'カットボール': (1.0, 0.4980392156862745, 0.054901960784313725), 'フォーク': (1.0, 0.7333333333333333, 0.47058823529411764), 'ツーシーム': (0.17254901960784313, 0.6274509803921569, 0.17254901960784313), 'チェンジアップ': (0.596078431372549, 0.8745098039215686, 0.5411764705882353), 'カーブ': (0.8392156862745098, 0.15294117647058825, 0.1568627450980392), 'シュート': (1.0, 0.596078431372549, 0.5882352941176471), 'ナックルカーブ': (0.5803921568627451, 0.403921568627451, 0.7411764705882353), 'シンカー': (0.7725490196078432, 0.6901960784313725, 0.8352941176470589), 'スプリット': (0.5490196078431373, 0.33725490196078434, 0.29411764705882354), '縦スライダー': (0.7686274509803922, 0.611764705882353, 0.5803921568627451), 'パワーカーブ': (0.8901960784313725, 0.4666666666666667, 0.7607843137254902), 'スローカーブ': (0.9686274509803922, 0.7137254901960784, 0.8235294117647058), 'スクリュー': (0.4980392156862745, 0.4980392156862745, 0.4980392156862745), 'スラーブ': (0.7803921568627451, 0.7803921568627451, 0.7803921568627451)}

色は、RGBで指定しています。
なお、このRGBはプログラムで作成(設定)しました。
今回は、話が逸れてしまうので、この部分の説明は省略します。

辞書型データの保存(永続化)

上記で作成した辞書型データを保存します。
このことをPythonでは、オブジェクトを永続化すると言うようです。

そして、オブジェクトの永続化で有名なのは、pickleです。
ただ、今回はjoblibを使います。

理由は、joblibの方が若干速いらしいからです。
いや、それ以上に新しいこと(知識)を試したいというだけですね。
正直、どっちでもいいです。

肝心の永続化方法は、以下のコードとなります。

import joblib

joblib.dump(color_dic, "color_dic.jb", compress=3) 

color_dicは、上記で作成した球種をキーにした辞書型データです。
これだけで、バイナリ化された「color_dic.jb」が作成されます。

今後は、これをもとに色リストを作成するということになります。
そうすれば、色バラバラ問題を解決できます。

辞書型データから色リストの作成

ここの部分は、プログラミングの説明がメインになります。
永続化した辞書型データをもとに色リスト(list型)を作成していきます。

まずは、「color_dic.jb」の読み込みです。

color_dic = joblib.load("color_dic.jb") 

これだけで終わりです。
辞書型データのまま保存されています。

ただし、Pythonでグラフの色を指定するには一工夫が必要です。
色を指定する際には、リスト型が基本です。

そのため、辞書型からリスト型のデータを作成する必要があります。
また、データ(ラベル含む)との順序が一致していないといけません。

抽象的な説明より、具体的な説明をします。
円グラフは次のコードで表示できます。

matplotlib.pyplot.pie(data_list, labels=label_list, colors=color_list)

円グラフ自体の説明は、公式サイトをご覧ください。
(まだ、円グラフの記事は投稿していませんでしたね。。。)

何が言いたいかと言うと、以下の3つのデータは順序が一致していないダメということです。

  • data_list(球数)
  • label_list(球種名)
  • color_list(色)

そこで、次のようなプログラミングで対応しています。

    color_list = []
    
    for key in data_list:
        
        try:
            color_code = color_dic[key]
        except:
            color_code = "#cccccc"
            
        color_list.append(color_code)

data_listの順序に合わせて、color_listを作成しています。
その際、color_dicが辞書型データであることを利用しています。

色を統一した円グラフ

色を統一した円グラフを表示しておきます。

オリックス山本由伸の全投球分析改良版

比較してどうでしょうか?
明らかに、わかりやすくなりました。

ストレートは、青色と固定されています。
フォーク、カーブなど他の球種も色が固定されています。

これは、他の投手の分析結果でも言えることです。
以下は、千賀 滉大投手の分析結果となります。

オリックス千賀滉大の全投球分析

千賀投手の場合でも、ストレートは青色です。
全投球、決め球の両方において。

つまり、一人の投手の分析内(全投球・決め球)における統一だけではないのです。
全分析内において、球種の色を統一できたということになります。
これもすべては、オブジェクトを永続化したおかげです。

それにしても、千賀投手はシンプルですね。
あと、カットボールがイメージより多いです。
メジャーを意識して、練習しているのでしょうか?

タイトルとURLをコピーしました