Pythonには強力な可視化ツールとしてmatplotlibがある事が有名です。ここでは、Pandasによるデータ処理、棒グラフの値の動的操作、GIFアニメーション作成までを全てPythonで処理する方法を紹介します。
こんにちは。wat(@watlablog)です。ここでは動的棒グラフ作成からGIFアニメーション作成までをやってみます!
本記事の目標
本記事で算出する動的棒グラフとは、以下のような動きのあるグラフです。
このように日付と連動して累積されていく検索数を見ていると、勢いのあるワード、順位の入れ替わりが一目瞭然です。
動きのあるプロットは使い所さえ見極めれば効果的なプレゼンを行う事ができます(但し、使いすぎは逆効果なので注意)。
今回はサンプルデータとして、有名なディープラーニングのフレームワーク(ディープラーニングのコードを組むために作られたライブラリ等の仕組み)を使いました(本当はもっとありますが、あくまで目的は動的グラフ作成のため)。
コーディングのキーポイント
本記事の最後に全コードを載せますが、ここに個別のコーディングキーポイントを示していきます。
Googleトレンドのcsvをそのまま使う
Googleトレンドをご存知でしょうか?
Googleトレンドは、入力したキーワードに対して過去の検索数を教えてくれるトレンド調査のツールです。このツールで色々なワードを比較する事で、今流行っている事を調査する事ができます。
データを分析する時、ユーザ側にファイルの加工を強いると途端に面倒になって使われないツールとなってしまう事があります。
そのため、本記事で紹介するプログラムコードは、Googleトレンドからダウンロードしたcsvをそのまま使う仕様としました。
以下はファイルを開くために作成した関数です。データサイエンスの世界で良く使われるPandasがかなり便利なので重宝しています。
Googleトレンドのcsvを一つずつ開き、プログラム内で.concatによる列方向の結合、列項目の書き換え、不要な行の削除、データ型の変換、累積和の計算といった一連の作業をこの関数の中で実行しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# ファイルオープンする関数(ファイル名のstringリストを引数にする) def file_open(file): df = pd.DataFrame() # 空のデータフレームを定義 # ファイルオープンしながらデータフレームを列方向に結合していくループ for i in range(len(file)): new = pd.read_csv(file[i] + '.csv', parse_dates=True) df = pd.concat([df, new], axis=1) df = df.drop('週') # Googleトレンドのcsvで元々入っていた項目をドロップ df.columns = file # ファイル名を列の項目名に変更 df = df.astype(int) # 型をintに変更 df = df.cumsum() # データの累積和を計算 return df |
Pandasのその他基本操作は「Python/Pandasの基本操作!データフレーム行列の取扱い」を是非ご覧下さい。
データ/ラベル/色を常に大きい順にソートする
上に示した目標の動的棒グラフは値の大小が上下のデータで入れ替わるとnp.sortを使って自動的に大きい順にソートされるようにしています。
データだけ入れ替わるとラベルや色が追従しないため、pd.Series.argsortを使ってPandasデータフレームのデータソートした順番を取得し、その順番でラベル順序や色リストの順序を入れ替えます。データとラベル、色の3つを同一順番にコントロールする事で上記動的棒グラフを実現させています。
1 2 3 4 5 6 |
data = df.iloc[i].astype(int) # i行目を抽出 data_sort = np.sort(data) # データをソート index = pd.Series.argsort(data) # ソートした順番を指標として取得 file_sort = file[index] # 軸をデータに合わせて並び替える color_sort = color[index] # 色をデータに合わせて並び替える |
画像ファイルを使ってGIFアニメーションを作る
当ブログでは「Pythonのmatplotlibアニメーションで楕円の軌跡!」にてmatplotlibのArtistAnimationを使ったGIFアニメーション作成を紹介しました。
この方法でも良いのですが、画像ファイルをフォルダに入れておいてGIFアニメーションを作るという方法を覚えておけば、matplotlibを使わないで処理する時でも汎用的に使える技術になるため、今回はあえて蓄積した画像ファイルを使う方法を選択しました。
以下のコードがGIFアニメーションを作成する関数です。'out'というディレクトリにあるファイルを全てリストしていますが、この時sortedを付けないと画像がめちゃくちゃな順番になってしまう事があるので注意が必要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# GIFアニメーションを作成 def create_gif(): path_list = sorted(glob.glob(os.path.join(*['out', '*']))) # ファイルパスをソートしてリストする imgs = [] # 画像をappendするための空配列を定義 # ファイルのフルパスからファイル名と拡張子を抽出 for i in range(len(path_list)): img = Image.open(path_list[i]) # 画像ファイルを1つずつ開く imgs.append(img) # 画像をappendで配列に格納していく # appendした画像配列をGIFにする imgs[0].save('dynamic-barplot.gif', save_all=True, append_images=imgs[1:], optimize=False, duration=100, loop=0) |
outディレクトリやファイルのリスト作成に拡張子を指定するといった事をすればより汎用的になると思います。
GIFの保存はimgs[0]で最初の画像を選択し、.saveメソッドでimgs[1:]とスライスを使って0番目以降の画像を選択します。dulationは1フレームあたりの持続時間、loop=0は無限ループをそれぞれ意味しています。loop=NとするとN回ループするGIFになります。
動的棒グラフを作成する全コード
最後に、全コードを以下に示します。forループでmatplotlibのグラフをいちいちクリアにしながら作っています(もっと効率良い方法あるかも?)。text()部分でdata.nameを使って日付をグラフにテキスト描画している所もポイントです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
import pandas as pd import numpy as np from PIL import Image import os import glob from matplotlib import pyplot as plt # ファイルオープンする関数(ファイル名のstringリストを引数にする) def file_open(file): df = pd.DataFrame() # 空のデータフレームを定義 # ファイルオープンしながらデータフレームを列方向に結合していくループ for i in range(len(file)): new = pd.read_csv(file[i] + '.csv', parse_dates=True) df = pd.concat([df, new], axis=1) df = df.drop('週') # Googleトレンドのcsvで元々入っていた項目をドロップ df.columns = file # ファイル名を列の項目名に変更 df = df.astype(int) # 型をintに変更 df = df.cumsum() # データの累積和を計算 return df # GIFアニメーションを作成 def create_gif(): path_list = sorted(glob.glob(os.path.join(*['out', '*']))) # ファイルパスをソートしてリストする imgs = [] # 画像をappendするための空配列を定義 # ファイルのフルパスからファイル名と拡張子を抽出 for i in range(len(path_list)): img = Image.open(path_list[i]) # 画像ファイルを1つずつ開く imgs.append(img) # 画像をappendで配列に格納していく # appendした画像配列をGIFにする imgs[0].save('dynamic-barplot.gif', save_all=True, append_images=imgs[1:], optimize=False, duration=100, loop=0) # matplotlibの横向きバープロットでトレンドの動的プロットを生成する関数 def dynamic_barplot(file, color): file = np.array(file) # fileをnumpyデータにする color = np.array(color) # colorをnumpyデータにする df = file_open(file) # ファイルオープンの関数を実行してデータフレームを得る axis = np.arange(len(file)) # プロットの横軸を生成 # データ行を1行ずつ抽出/ソート/プロットをするループ for i in range(len(df)): # 進捗モニタのためにループ10回毎にiを出力 if i%10 == 0: print('i=',i) # 事前グラフ設定------------------------------------- # フォントの種類とサイズを設定する plt.rcParams['font.size'] = 14 plt.rcParams['font.family'] = 'Times New Roman' # 目盛を内側にする plt.rcParams['xtick.direction'] = 'in' plt.rcParams['ytick.direction'] = 'in' # グラフの上下左右に目盛線を付ける fig = plt.figure() ax1 = fig.add_subplot(111) ax1.yaxis.set_ticks_position('both') ax1.xaxis.set_ticks_position('both') # 軸のラベルを設定する ax1.set_xlabel('Number of Search') ax1.set_xlim(0,15000) # 事前グラフ設定------------------------------------- data = df.iloc[i].astype(int) # i行目を抽出 data_sort = np.sort(data) # データをソート index = pd.Series.argsort(data) # ソートした順番を指標として取得 file_sort = file[index] # 軸をデータに合わせて並び替える color_sort = color[index] # 色をデータに合わせて並び替える # データプロット ax1.barh(axis, data_sort, tick_label=file_sort, color=color_sort) plt.text(0, len(data) + 0.01, data.name, fontsize=20) # グラフを表示する fig.tight_layout() # outフォルダが無い時に新規作成 if os.path.exists('out'): pass else: os.mkdir('out') # 画像保存パスを準備 path = os.path.join(*['out', str("{:05}".format(i)) + '.png']) # 画像を保存する plt.savefig(path) plt.close() # GIFアニメーションを作成する関数を実行する create_gif() return df # fileとカラーをリストで準備して動的棒グラフをGIFで作成する file = ['TensorFlow', 'PyTorch', 'Chainer', 'keras', 'MxNet'] # ファイル名のリスト color = ['r', 'g', 'b', 'y', 'm'] # 色のリスト df = dynamic_barplot(file, color) |
まとめ
本記事では動的棒グラフ(この名称は当ブログだけかも?)の作り方を紹介しました。
コーディングのキーポイントとして、Googleトレンドのデータをそのまま使いユーザにデータ加工をさせないようにしたり、データソートをしたり、GIFを作ったりする所を紹介しました。
もしかしたらplotlyとか使えば簡単にもっと見栄えの良いグラフが作れるかも知れませんが、そっちはまだ調査していません。
今回はよくTwitterとかで流れてくる棒グラフの動画(テスラ社がぐんぐん成長していく様子で有名なやつ等)を自分で作ってみたらどうかなと思ってついやっただけです。公開はしましたが後悔はしていません。
特に躓く事無くすんなりと動きのあるグラフが作れました!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!