英文:
Replace x-axis index of imshow with frequency (kHz)
问题
以下是您提供的代码的翻译部分:
我有以下绘图
导入numpy为np
导入matplotlib.pyplot为plt
fs = 1000
t = np.arange(0, 0.1, 1/fs)
N = len(t)
f_bin = fs / N
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2 * np.pi * 100 * t)), np.fft.fft(np.sin(2 * np.pi * 200 * t)), np.fft.fft(np.sin(2 * np.pi * 300 * t))]
M = np.absolute(X)
fig, ax = plt.subplots()
im = ax.imshow(M[:,:len(M[0,:]) // 2], cmap='viridis', aspect=1)
clb = fig.colorbar(im, ax=ax)
clb.ax.set_title("Magnitude")
ax.set_xlabel(f"Index (f[{round(100/f_bin)}] = {f[round(100/f_bin)]} Hz)")
ax.set_ylabel("# FFT")
ax.set_title("Built-in FFT")
plt.show()
这段代码产生了以下结果:
是否有一种(好的)方法可以使用f_bin
和f
将“Index”转换为实际的“frequency bin”?
我希望我没有忽略在Stack Overflow
中已经存在的解决方案。
<details>
<summary>英文:</summary>
I have following plot
import numpy as np
import matplotlib.pyplot as plt
fs = 1000
t = np.arange(0, 0.1, 1/fs)
N = len(t)
f_bin = fs / N
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2 * np.pi * 100 * t)), np.fft.fft(np.sin(2 * np.pi * 200 * t)), np.fft.fft(np.sin(2 * np.pi * 300 * t))]
M = np.absolute(X)
fig, ax = plt.subplots()
im = ax.imshow(M[:,:len(M[0,:]) // 2], cmap='viridis', aspect=1)
clb = fig.colorbar(im, ax=ax)
clb.ax.set_title("Magnitude")
ax.set_xlabel(f"Index (f[{round(100/f_bin)}] = {f[round(100/f_bin)]} Hz)")
ax.set_ylabel("# FFT")
ax.set_title(f"Built-in FFT")
plt.show()
which results in
[![enter image description here][2]][2]
Is there a (nice) solution to transform the "Index" into the actual "frequency bin" by using `f_bin` and `f`
[![enter image description here][1]][1]
I hope I haven't overlooked some already existing solutions in `Stack Overflow`.
[1]: https://i.stack.imgur.com/cM1ck.png
[2]: https://i.stack.imgur.com/ZKsSi.png
</details>
# 答案1
**得分**: 1
你可以使用`ax.set_xticklabels`为你的xtick标签设置新值:
```python
import numpy as np
import matplotlib.pyplot as plt
fs = 1000
t = np.arange(0, 0.1, 1/fs)
N = len(t)
f_bin = fs / N
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2 * np.pi * 100 * t)), np.fft.fft(np.sin(2 * np.pi * 200 * t)), np.fft.fft(np.sin(2 * np.pi * 300 * t))]
M = np.absolute(X)
fig, ax = plt.subplots()
im = ax.imshow(M[:,:len(M[0,:]) // 2], cmap='viridis', aspect=1)
clb = fig.colorbar(im, ax=ax)
clb.ax.set_title("Magnitude")
ax.set_xlabel(f"Frequency (kHz)")
ax.set_ylabel("# FFT")
ax.set_title(f"Built-in FFT")
ax.set_xticklabels([x/100 for x in ax.get_xticks()])
plt.show()
输出:
英文:
You can set new values for your xtick labels with ax.set_xticklabels
:
import numpy as np
import matplotlib.pyplot as plt
fs = 1000
t = np.arange(0, 0.1, 1/fs)
N = len(t)
f_bin = fs / N
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2 * np.pi * 100 * t)), np.fft.fft(np.sin(2 * np.pi * 200 * t)), np.fft.fft(np.sin(2 * np.pi * 300 * t))]
M = np.absolute(X)
fig, ax = plt.subplots()
im = ax.imshow(M[:,:len(M[0,:]) // 2], cmap='viridis', aspect=1)
clb = fig.colorbar(im, ax=ax)
clb.ax.set_title("Magnitude")
ax.set_xlabel(f"Frequency (kHz)")
ax.set_ylabel("# FFT")
ax.set_title(f"Built-in FFT")
ax.set_xticklabels([x/100 for x in ax.get_xticks()])
plt.show()
Output:
答案2
得分: 1
关于显示类似这样的二维数据并设置坐标轴时,你应该使用 pcolormesh
。在这种情况下,你的 x 值由 f/1000
设置,y 值由 M
中的行数枚举(在这种情况下为 3)。假设你仍然想要一个宽图,你可以设置纵横比以实现这一点。我还将 y 刻度更改为只显示 y 值。
import numpy as np
import matplotlib.pyplot as plt
plt.close("all")
fs = 1000
t = np.arange(0, 0.1, 1/fs)
f_bin = fs/len(t)
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2*np.pi*100*t)),
np.fft.fft(np.sin(2*np.pi*200*t)),
np.fft.fft(np.sin(2*np.pi*300*t))]
M = np.absolute(X)
fig, ax = plt.subplots()
s = np.s_[:, :len(M[0, :]) // 2]
x = f展开收缩]/1000
y = np.arange(M.shape[0])
p = ax.pcolormesh(x, y, M展开收缩, cmap="viridis")
fig.colorbar(p, ax=ax, label="Magnitude")
ax.set_yticks(y)
ax.set_aspect(10*y.max()/fs)
ax.set_xlabel("Frequency [kHz]")
ax.set_ylabel("# FFT")
ax.set_title("Built-in FFT")
fig.show()
[1]: https://i.stack.imgur.com/yKcGU.png
英文:
When it comes to showing 2D data like this while setting the axes, you should use pcolormesh
. In this case, your x values are set by f/1000
and your y values are enumerated by the number of rows in M
(in this case: 3). Assuming you still want a fat plot, you can set the aspect ratio to achieve that. I also changed the y-ticks to just be the y values.
import numpy as np
import matplotlib.pyplot as plt
plt.close("all")
fs = 1000
t = np.arange(0, 0.1, 1/fs)
f_bin = fs/len(t)
f = np.arange(0, fs, f_bin)
X = [np.fft.fft(np.sin(2*np.pi*100*t)),
np.fft.fft(np.sin(2*np.pi*200*t)),
np.fft.fft(np.sin(2*np.pi*300*t))]
M = np.absolute(X)
fig, ax = plt.subplots()
s = np.s_[:, :len(M[0, :]) // 2]
x = f展开收缩]/1000
y = np.arange(M.shape[0])
p = ax.pcolormesh(x, y, M展开收缩, cmap="viridis")
fig.colorbar(p, ax=ax, label="Magnitude")
ax.set_yticks(y)
ax.set_aspect(10*y.max()/fs)
ax.set_xlabel("Frequency [kHz]")
ax.set_ylabel("# FFT")
ax.set_title("Built-in FFT")
fig.show()
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论