やりたいこと
時系列信号・データを扱っていると、その信号に対する各種イベント・ラベル(例:どんな音が鳴っているか)を時間とともに表示したいと思うことが多々あります。
そこで、Pythonの matplotlib
で時間波形に対するイベント(ラベル)のタイムラインチャートを表示する方法を調べて実装してみました。
基礎編
plt.broken_barh(xranges, yrange, *, data=None, **kwargs)
を使います。
この関数は、水平軸方向に同じy軸幅の矩形領域をいくつも描画できる関数です。xranges
に各矩形領域の情報 (xmin, xwidth)
の配列を与えます。yrange
には(ymin, ywidth)
を与えます((ドキュメントでは (ymin, ymax)
となっている…))。
オプションとしては、例えば facecolors
で色を指定したりできます。
import numpy as np import matplotlib.pyplot as plt labels = ["A", "B", "C"] plt.clf() # broken_barh( [(xmin, xwidth), (xmin, xwidth), ...], (ymin, ywidth)) plt.broken_barh([(0, 1.0)], (0, 1), facecolors='red') plt.broken_barh([(0.5, 0.5), (1.5, 0.3)], (1, 1), facecolors='blue') plt.broken_barh([(0.5, 1.2)], (2, 1), facecolors='green') plt.ylim(0, 4) plt.xlim(0, 2) plt.title('Timeline') plt.xlabel('Time') plt.yticks(np.arange(0, 3)+0.5, labels) plt.show()
応用編
楽曲に対して、トラック(楽器)、セクション(Aメロ、サビ、etc.)ラベルをタイムライン表示してみました。
今は時間区間情報を手動で打ち込んでいますが、自動で算出されたら便利な気がします。
import librosa import os import numpy as np import matplotlib.pyplot as plt import matplotlib.cm as cm import matplotlib as mpl filepath = "audio/Retrograde Amnesia.wav" y, sr = librosa.load(filepath, mono=True) duration = len(y) // sr class Timeline: def __init__(self, data, label): # data = [(xmin, xwidth), (xmin, xwidth), ... ] self.data = [ (v[0], np.maximum(v[1]-v[0], 0)) for v in data] self.label = label timeline_tracks = [ # Timeline(([xmin, xmax)], label_str, color) Timeline([(0.8, 85)], "Drums"), Timeline([(0.8, 85)], "Bass"), Timeline([(0.8, 22.5), (36.5, 85)], "Dist. Gt. L"), Timeline([(22.5, 36.5)], "Gt. L with Phaser"), Timeline([(0.8, 85)], "Dist. Gt. R"), Timeline([(22.5, 36.5), (43.5, 85)], "Vocal"), Timeline([(8, 22.5), (36.5, 43.5)], "Lead Guitar"), ] timeline_sections= [ # Timeline(([xmin, xmax)], label_str, color) Timeline([(22.5, 36.5), (43.5, 57)], "Verse"), Timeline([(57, 61)], "Pre-Chorus"), Timeline([(61, 85)], "Chorus"), Timeline([(0.8, 22.5)], "Intro"), Timeline([(36.5, 43.5)], "Interlude"), ] plt.clf() mpl.rcParams['axes.xmargin'] = 0 mpl.rcParams['axes.ymargin'] = 0 plt.subplot(3,1,1) plt.plot(np.linspace(0, duration, len(y)), np.sign(y)*(np.abs(y)**2), c="c") plt.xlabel("Time (sec)") plt.title(os.path.split(filepath)[1]) plt.subplot(3,1,2) labels = [] for k, timeline in enumerate(timeline_tracks): plt.broken_barh(timeline.data, (k, 1), facecolors=cm.jet(k/len(timeline_tracks))) labels.append(timeline.label) plt.ylim(0, len(timeline_tracks) ) plt.xlim(0, duration) plt.xlabel('Time (sec)') plt.yticks(np.arange(0, len(labels))+0.5, labels) plt.title("Timeline of tracks") plt.subplot(3,1,3) labels = [] for k, timeline in enumerate(timeline_sections): plt.broken_barh(timeline.data, (k, 1), facecolors=cm.jet(k/len(timeline_sections))) labels.append(timeline.label) plt.ylim(0, len(timeline_sections) ) plt.xlim(0, duration) plt.xlabel('Time (sec)') plt.yticks(np.arange(0, len(labels))+0.5, labels) plt.title("Timeline of sections") plt.tight_layout() plt.show()
補足
使用楽曲は、幻象アリス:"Noctiflora"より "Retrograde Amnesia" (0:00-1:25) です。