如何拉伸 matplotlib 频谱图的 x 轴?
How do I stretch the x-axis of a matplotlib spectrogram?
抱歉,如果这是一个非常明显的问题。我正在使用 matplotlib 生成一些频谱图,用作机器学习模型中的训练数据。频谱图是音乐的短片,我想模拟随机加速或减慢歌曲以创建数据变化。我在下面展示了生成每个频谱图的代码。我临时修改了它以生成 2 张从歌曲中的同一点开始的图像,一张有变化,一张没有,以便比较它们,看看它是否按预期工作。
from pydub import AudioSegment
import matplotlib.pyplot as plt
import numpy as np
BPM_VARIATION_AMOUNT = 0.2
FRAME_RATE = 22050
CHUNK_SIZE = 2
BUFFER = FRAME_RATE * 5
def generate_random_specgram(track):
# Read audio data from file
audio = AudioSegment.from_file(track.location)
audio = audio.set_channels(1).set_frame_rate(FRAME_RATE)
samples = audio.get_array_of_samples()
start = np.random.randint(BUFFER, len(samples) - BUFFER)
chunk = samples[start:start + int(CHUNK_SIZE * FRAME_RATE)]
# Plot specgram and save to file
filename = ('specgrams/%s-%s-%s.png' % (track.trackid, start, track.bpm))
plt.figure(figsize=(2.56, 0.64), frameon=False).add_axes([0, 0, 1, 1])
plt.axis('off')
plt.specgram(chunk, Fs = FRAME_RATE)
plt.savefig(filename)
plt.close()
# Perform random variations to the BPM
frame_rate = FRAME_RATE
bpm = track.bpm
variation = 1 - BPM_VARIATION_AMOUNT + (
np.random.random() * BPM_VARIATION_AMOUNT * 2)
bpm *= variation
bpm = round(bpm, 2)
# I thought this next line should have been /= but that stretched the wrong way?
frame_rate *= (bpm / track.bpm)
# Read audio data from file
chunk = samples[start:start + int(CHUNK_SIZE * frame_rate)]
# Plot specgram and save to file
filename = ('specgrams/%s-%s-%s.png' % (track.trackid, start, bpm))
plt.figure(figsize=(2.56, 0.64), frameon=False).add_axes([0, 0, 1, 1])
plt.axis('off')
plt.specgram(chunk, Fs = frame_rate)
plt.savefig(filename)
plt.close()
我想通过改变给 specgram 函数的 Fs 参数,这会沿着 x 轴拉伸数据,但它似乎正在调整整个图的大小并在图的顶部引入白色 space图像以奇怪和不可预测的方式。我确定我遗漏了什么,但我看不到它是什么。下面是一张图片来说明我得到的结果。
帧率是一个固定数字,它只取决于您的数据,如果您更改它,您将有效地 "stretch" x 轴,但方式不对。例如,如果您有 1000 个数据点对应 1 秒,则您的帧率(或更好的采样频率)将为 1000。如果您的信号是一个简单的 200Hz 正弦波,它会及时稍微增加频率,specgram
将是:
t = np.linspace(0, 1, 1000)
signal = np.sin((200*2*np.pi + 200*t) * t)
frame_rate = 1000
plt.specgram(signal, Fs=frame_rate);
如果您更改帧率,您将获得错误的 x 轴和 y 轴刻度。如果您将帧速率设置为 500,您将拥有:
t = np.linspace(0, 1, 1000)
signal = np.sin((200*2*np.pi + 200*t) * t)
frame_rate = 500
plt.specgram(signal, Fs=frame_rate);
情节非常相似,但这次是错误的:你在x轴上几乎有2秒,而你应该只有1秒,而且你读取的起始频率是100Hz而不是200Hz。
总之,您设置的采样频率需要正确。如果你想拉伸情节,你可以使用像 plt.xlim(0.2, 0.4)
这样的东西。如果你想避免绘图顶部的白带,你可以手动将 ylim
设置为帧速率的一半:
plt.ylim(0, frame_rate/2)
之所以可行,是因为傅立叶变换的简单属性和 Nyquist-Shannon theorem。
我的问题的解决方案是设置绘图的 xlim 和 ylim。这是我的测试文件中的代码,我终于在其中删除了所有奇怪的空格:
from pydub import AudioSegment
import numpy as np
import matplotlib.pyplot as plt
BUFFER = 5
FRAME_RATE = 22050
SAMPLE_LENGTH = 2
def plot(audio_file, bpm, variation=1):
audio = AudioSegment.from_file(audio_file)
audio = audio.set_channels(1).set_frame_rate(FRAME_RATE)
samples = audio.get_array_of_samples()
chunk_length = int(FRAME_RATE * SAMPLE_LENGTH * variation)
start = np.random.randint(
BUFFER * FRAME_RATE,
len(samples) - (BUFFER * FRAME_RATE) - chunk_length)
chunk = samples[start:start + chunk_length]
plt.figure(figsize=(5.12, 2.56)).add_axes([0, 0, 1, 1])
plt.specgram(chunk, Fs=FRAME_RATE * variation)
plt.xlim(0, SAMPLE_LENGTH)
plt.ylim(0, FRAME_RATE / 2 * variation)
plt.savefig('specgram-%f.png' % (bpm * variation))
plt.close()
抱歉,如果这是一个非常明显的问题。我正在使用 matplotlib 生成一些频谱图,用作机器学习模型中的训练数据。频谱图是音乐的短片,我想模拟随机加速或减慢歌曲以创建数据变化。我在下面展示了生成每个频谱图的代码。我临时修改了它以生成 2 张从歌曲中的同一点开始的图像,一张有变化,一张没有,以便比较它们,看看它是否按预期工作。
from pydub import AudioSegment
import matplotlib.pyplot as plt
import numpy as np
BPM_VARIATION_AMOUNT = 0.2
FRAME_RATE = 22050
CHUNK_SIZE = 2
BUFFER = FRAME_RATE * 5
def generate_random_specgram(track):
# Read audio data from file
audio = AudioSegment.from_file(track.location)
audio = audio.set_channels(1).set_frame_rate(FRAME_RATE)
samples = audio.get_array_of_samples()
start = np.random.randint(BUFFER, len(samples) - BUFFER)
chunk = samples[start:start + int(CHUNK_SIZE * FRAME_RATE)]
# Plot specgram and save to file
filename = ('specgrams/%s-%s-%s.png' % (track.trackid, start, track.bpm))
plt.figure(figsize=(2.56, 0.64), frameon=False).add_axes([0, 0, 1, 1])
plt.axis('off')
plt.specgram(chunk, Fs = FRAME_RATE)
plt.savefig(filename)
plt.close()
# Perform random variations to the BPM
frame_rate = FRAME_RATE
bpm = track.bpm
variation = 1 - BPM_VARIATION_AMOUNT + (
np.random.random() * BPM_VARIATION_AMOUNT * 2)
bpm *= variation
bpm = round(bpm, 2)
# I thought this next line should have been /= but that stretched the wrong way?
frame_rate *= (bpm / track.bpm)
# Read audio data from file
chunk = samples[start:start + int(CHUNK_SIZE * frame_rate)]
# Plot specgram and save to file
filename = ('specgrams/%s-%s-%s.png' % (track.trackid, start, bpm))
plt.figure(figsize=(2.56, 0.64), frameon=False).add_axes([0, 0, 1, 1])
plt.axis('off')
plt.specgram(chunk, Fs = frame_rate)
plt.savefig(filename)
plt.close()
我想通过改变给 specgram 函数的 Fs 参数,这会沿着 x 轴拉伸数据,但它似乎正在调整整个图的大小并在图的顶部引入白色 space图像以奇怪和不可预测的方式。我确定我遗漏了什么,但我看不到它是什么。下面是一张图片来说明我得到的结果。
帧率是一个固定数字,它只取决于您的数据,如果您更改它,您将有效地 "stretch" x 轴,但方式不对。例如,如果您有 1000 个数据点对应 1 秒,则您的帧率(或更好的采样频率)将为 1000。如果您的信号是一个简单的 200Hz 正弦波,它会及时稍微增加频率,specgram
将是:
t = np.linspace(0, 1, 1000)
signal = np.sin((200*2*np.pi + 200*t) * t)
frame_rate = 1000
plt.specgram(signal, Fs=frame_rate);
如果您更改帧率,您将获得错误的 x 轴和 y 轴刻度。如果您将帧速率设置为 500,您将拥有:
t = np.linspace(0, 1, 1000)
signal = np.sin((200*2*np.pi + 200*t) * t)
frame_rate = 500
plt.specgram(signal, Fs=frame_rate);
情节非常相似,但这次是错误的:你在x轴上几乎有2秒,而你应该只有1秒,而且你读取的起始频率是100Hz而不是200Hz。
总之,您设置的采样频率需要正确。如果你想拉伸情节,你可以使用像 plt.xlim(0.2, 0.4)
这样的东西。如果你想避免绘图顶部的白带,你可以手动将 ylim
设置为帧速率的一半:
plt.ylim(0, frame_rate/2)
之所以可行,是因为傅立叶变换的简单属性和 Nyquist-Shannon theorem。
我的问题的解决方案是设置绘图的 xlim 和 ylim。这是我的测试文件中的代码,我终于在其中删除了所有奇怪的空格:
from pydub import AudioSegment
import numpy as np
import matplotlib.pyplot as plt
BUFFER = 5
FRAME_RATE = 22050
SAMPLE_LENGTH = 2
def plot(audio_file, bpm, variation=1):
audio = AudioSegment.from_file(audio_file)
audio = audio.set_channels(1).set_frame_rate(FRAME_RATE)
samples = audio.get_array_of_samples()
chunk_length = int(FRAME_RATE * SAMPLE_LENGTH * variation)
start = np.random.randint(
BUFFER * FRAME_RATE,
len(samples) - (BUFFER * FRAME_RATE) - chunk_length)
chunk = samples[start:start + chunk_length]
plt.figure(figsize=(5.12, 2.56)).add_axes([0, 0, 1, 1])
plt.specgram(chunk, Fs=FRAME_RATE * variation)
plt.xlim(0, SAMPLE_LENGTH)
plt.ylim(0, FRAME_RATE / 2 * variation)
plt.savefig('specgram-%f.png' % (bpm * variation))
plt.close()