【python】matplotlibでオクターブバンドの3Dグラフを描きたい

プログラミング

やりたいこと

時間が行のインデックスに、オクターブバンドの中心周波数が列のインデックスになってるようなDataFrameを使って3Dグラフを描きたいです。

今回はESC-50の音声データを使用しており、オクターブ解析した後のデータは以下のような形で格納されています。

index 列に時間が格納されており、各列の列名にはオクターブバンドの中心周波数が格納されています。

なお、環境としてはGoogle Colaboratoryを使用しています。

データの一部

コード例

以下のコードで所望の動きを実現することができました。

上手くいくと次のような3Dのグラフを描画することができます。

3Dグラフ

書き方が2通りありますが、自分の流派の方を参考にしてください。

書き方の違いは最後に補足します。

pyplotインターフェースを使う書き方

import matplotlib.pyplot as plt

plt.pcolor(df.index, np.arange(0, len(df.columns)), df.T, cmap=cm.jet, vmin = -80, vmax = -20)
plt.yticks(np.arange(0, len(df.columns), 4), df.columns[::4])
plt.colorbar()

データ自体はdfに格納されているものとします。

ポイントはY軸の値には各オクターブバンドの中心周波数を与えるのではなく、一度0~バンド数で指定した後に、改めてY軸のラベルを置き換えているという点です(3行目のnp.arange)。

plt.yticksのところがラベルを置き換えているところに相当します。

ちなみに直接Y軸の値としてオクターブバンドの中心周波数を与えるとうまくいきませんでした。

ラベルは4個飛ばしで描画してますが、見栄えがそれっぽかったので4個飛ばしにしているだけで、特に理由はないです。

オブジェクト指向インターフェースを使う書き方

import matplotlib.pyplot as plt

fig = plt.figure()
ax = fig.add_subplot(1,1,1)
c = ax.pcolor(df.index, np.arange(0, len(df.columns) + 1), df.T, cmap=cm.jet, vmin = -80, vmax = -20)
ax.set_yticks(np.arange(len(df.columns))[::4])
ax.set_yticklabels(np.array(df.columns)[::4])
fig.colorbar(c, ax=ax)

こちらはオブジェクト指向インターフェースを使った書き方です。

上のpyplotインターフェースと違うところは、いったんset_yticksでY軸を0~バンド幅に設定した後で、set_yticklabelsを使用してラベルの値を設定しているというところです。

先ほどと同様にラベルは4個飛ばしにしていますが、いい感じの値を使用してください。

ラベルを飛ばさないとすべてのオクターブバンドがY軸に表示されてしまい、見た目がよろしくなかったです。

おまけ:matplotlibのグラフインターフェースについて

ネット上でmatplotlibの使い方を調べると、「plt.なんとか」と書く方法と「ax.なんとか」と書く方法が存在します。

これらの違いですが、「plt.なんとか」のほうはpyplotインターフェースと呼ばれており、最後に使ったグラフの設定を勝手に変更してくれます。

利用方法が簡単なため、グラフをさっと表示するには向いています。

ただし、細かい調整をするのには向いていないと感じます。

一方で「ax.なんとか」はオブジェクト指向インターフェースと呼ばれており、matplotlibのグラフの各要素のオブジェクトを自分で明示的に取得し、そのオブジェクトに任意の設定を行うことができます。

グラフ表示にはひと手間かかってしまうものの、細かい調整が可能となります。

コメント

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