How to align axis of spectrogram visualisations in Librosa or Matplotlib ?
Consider this example, from Librosa's documentation:
as you can see, the rolloff are aligned with the spectrogram. I can't replicate the figure with my own audio.
The y-axis is never aligned.
Try:
sr = 250000
n_fft = 2048
hop_length=256
win_length = 1024
fmin = 220
S, phase = librosa.magphase(librosa.stft(filtered_audio))
sftf_spec = librosa.stft(filtered_audio, n_fft=n_fft, hop_length=hop_length)
S = np.abs(sftf_spec)
rolloff = librosa.feature.spectral_rolloff(S=S,
sr=sr,
n_fft=n_fft,
hop_length=hop_length,
win_length = win_length
)
amplitude_spec = librosa.amplitude_to_db(S,
ref=np.max)
rolloff_min = librosa.feature.spectral_rolloff(S=S, sr=sr, roll_percent=0.15)
fig, ax = plt.subplots()
librosa.display.specshow(amplitude_spec,
y_axis='log', x_axis='time', ax=ax)
ax.plot(librosa.times_like(rolloff), rolloff[0], label='Roll-off frequency (0.85)')
ax.plot(librosa.times_like(rolloff), rolloff_min[0], color='w',
label='Roll-off frequency (0.15)')
ax.legend(loc='lower right')
ax.set(title='log Power spectrogram')
If you need to replicate, you can try download the audio wav :
https://drive.google.com/file/d/1UCUWAaczzejTN9m_y-usjPbG8__1mWI1/view?usp=sharing
filtered_audio = np.array([[ #copy ]])
I got this:
and if I set the rate in specshow, I got this:
librosa.display.specshow(amplitude_spec,
sr=sr,
y_axis='log', x_axis='time', ax=ax)
I want to have the bandwidth following the same scale of the spectrogram they were build from...
One has to be diligent in passing all the relevant parameters. In your code, both the call to specshow
, times_like
, and spectral_rolloff
were missing key arguments like sr
, hop_length
et.c. Without these, both the X and Y axis will typically be off.
When ensuring this, the results look to be correct. See complete code below.
import librosa
import numpy as np
import pandas
from matplotlib import pyplot as plt
import librosa.display
def plot_spectral(audio, sr, hop_length=256, win_length=1024, n_fft=2048):
# shared parameters
spec_params = dict(n_fft=n_fft, hop_length=hop_length, win_length=win_length)
# compute
sftf_spec = librosa.stft(audio, **spec_params)
S = np.abs(sftf_spec)
amplitude_spec = librosa.amplitude_to_db(S, ref=np.max)
up = librosa.feature.spectral_rolloff(S=S, sr=sr, **spec_params, roll_percent=0.85)
rolloff = pandas.DataFrame({
'upper': librosa.feature.spectral_rolloff(S=S, sr=sr, **spec_params, roll_percent=0.85)[0, :],
'lower': librosa.feature.spectral_rolloff(S=S, sr=sr, **spec_params, roll_percent=0.15)[0, :],
})
rolloff['time'] = librosa.times_like(rolloff['lower'], sr=sr, hop_length=hop_length)
fig, ax = plt.subplots()
librosa.display.specshow(amplitude_spec, sr=sr, **spec_params,
y_axis='log', x_axis='time', ax=ax, )
ax.plot(rolloff['time'], rolloff['upper'], color='blue', label='Roll-off frequency (0.85)')
ax.plot(rolloff['time'], rolloff['lower'], color='white', label='Roll-off frequency (0.15)')
ax.legend(loc='lower right')
ax.set(title='log Power spectrogram')
fig.savefig('spectral-rolloffs.png')
def load_data():
p = 'test_wav_segment.wav'
audio, sr = librosa.load(p, sr=None)
return audio, sr
audio, sr = load_data()
plot_spectral(audio, sr=sr)
The use of Pandas is not critical. However it keeps the related data together, and ensures that the times array is equal length to the rolloffs which they are fo.