用频率(kHz)替换imshow的x轴索引

huangapple go评论107阅读模式
英文:

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()

这段代码产生了以下结果:

用频率(kHz)替换imshow的x轴索引

是否有一种(好的)方法可以使用f_binf将“Index”转换为实际的“frequency bin”?

用频率(kHz)替换imshow的x轴索引

我希望我没有忽略在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=&#39;viridis&#39;, aspect=1)
    clb = fig.colorbar(im, ax=ax)
    clb.ax.set_title(&quot;Magnitude&quot;)
    ax.set_xlabel(f&quot;Index (f[{round(100/f_bin)}] = {f[round(100/f_bin)]} Hz)&quot;)
    ax.set_ylabel(&quot;# FFT&quot;)
    ax.set_title(f&quot;Built-in FFT&quot;)
    plt.show()

which results in

[![enter image description here][2]][2]

Is there a (nice) solution to transform the &quot;Index&quot; into the actual &quot;frequency bin&quot; by using `f_bin` and `f`

[![enter image description here][1]][1]

I hope I haven&#39;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()

输出:

用频率(kHz)替换imshow的x轴索引

英文:

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=&#39;viridis&#39;, aspect=1)
clb = fig.colorbar(im, ax=ax)
clb.ax.set_title(&quot;Magnitude&quot;)
ax.set_xlabel(f&quot;Frequency (kHz)&quot;)
ax.set_ylabel(&quot;# FFT&quot;)
ax.set_title(f&quot;Built-in FFT&quot;)
ax.set_xticklabels([x/100 for x in ax.get_xticks()])
plt.show()

Output:

用频率(kHz)替换imshow的x轴索引

答案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()

用频率(kHz)替换imshow的x轴索引


[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(&quot;all&quot;)

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=&quot;viridis&quot;)
fig.colorbar(p, ax=ax, label=&quot;Magnitude&quot;) ax.set_yticks(y) ax.set_aspect(10*y.max()/fs) ax.set_xlabel(&quot;Frequency [kHz]&quot;) ax.set_ylabel(&quot;# FFT&quot;) ax.set_title(&quot;Built-in FFT&quot;) fig.show()

用频率(kHz)替换imshow的x轴索引

huangapple
  • 本文由 发表于 2023年8月10日 14:04:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/76872995.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定