如何根据ylim缩放色条

3 投票
1 回答
1619 浏览
提问于 2025-04-17 18:02

我正在使用matplotlib的specgram函数绘制我的数据的频谱图。

Pxx, freqs, bins= mlab.specgram(my_data,NFFT=nFFT,Fs=Fs,detrend=mlab.detrend_linear,noverlap=n_overlap,pad_to=p_to,scale_by_freq=True)

为了参考,"freqs"、"bins"(也就是时间)和"Pxx"的形状分别是(1025,)、(45510,)和(1025,45510)。

在这里,我定义了函数的参数。

Fs = 10E6      # Sampling Rate
w_length= 256      # window length
nFFT=2 * w_length
n_overlap=np.fix(w_length/2)
p_to = 8 *w_length

这个图的频率范围(y轴)是从0到5E6赫兹。当我绘制它时,我想查看不同的频率范围,比如从100E3赫兹到1E6赫兹。如果我改变图的y轴限制,颜色条的范围不会改变,也就是说,它不会更新以反映这个“新”的频率范围内的信号值。我能否找到一种方法,让颜色条在我改变y轴范围时也能相应更新?

interp='nearest'
cmap=seismic
fig = plt.figure()
ax1=fig.add_subplot(111)
img1=ax1.imshow(Pxx, interpolation=interp, aspect='auto',extent=extent,cmap=cmap)
ax1.autoscale(enable=True,axis='x',tight=True)
ax1.autoscale(enable=True,axis='y',tight=True)
ax1.set_autoscaley_on(False)
ax1.set_ylim([100E3,1E6])
fig.colorbar(img1)
plt.show()

我想,如果我能找到在感兴趣的频率范围内,Pxx的最大值和最小值分别对应的上限和下限频率,那么我就可以用这些值来设置颜色条的限制,比如:

img1.set_clim(min_val, max_val) 

我可以一般性地找到Pxx的最大值和最小值,并返回它们的索引,方法是:

import numpy as np
>>> np.unravel_index(Pxx.argmax(),Pxx.shape)
(20, 31805)
>>> np.unravel_index(Pxx.argmin(),Pxx.shape)
(1024, 31347)

我该如何找到与感兴趣的频率范围对应的Pxx值呢?

我可以做类似以下的操作,大致找到在"freqs"中100E3和1E6大约位于哪里(并取每个的第一个或最后一个值)……

   fmin_index= [i for i,x in enumerate(freqs) if x >= 100E3][0]
   fmax_index= [i for i,x in enumerate(freqs) if x >= 1000E3][0]

或者

   fmin_index= [i for i,x in enumerate(freqs) if x <= 100E3][-1]
   fmax_index= [i for i,x in enumerate(freqs) if x <= 1000E3][-1]

然后可能

min_val = np.min(Pxx[fmin_index,:])
max_val = np.min(Pxx[fmax_index,:])

最后

img1.set_clim(min_val, max_val)

不幸的是,这似乎没有奏效,因为颜色条上的值范围看起来不正确。一定有更好、更简单、更准确的方法来做到这一点。

1 个回答

1

与其在图表中调整限制,不如直接改变你要绘制的数据,让colorbar自己处理。这是一个在pylab环境中运行的简单示例:

#some random data
my_data = np.random.random(2048)

#### Your Code
Fs = 10E6      # Sampling Rate
w_length= 256      # window length
nFFT=2 * w_length
n_overlap=np.fix(w_length/2)
p_to = 8 *w_length

Pxx, freqs, bins= mlab.specgram(my_data,NFFT=nFFT,Fs=Fs,
                                detrend=mlab.detrend_linear,
                                noverlap=n_overlap,
                                pad_to=p_to,scale_by_freq=True)

#find a maximum frequency index
maxfreq = 1E5 #replace by your maximum freq
if maxfreq:
    lastfreq = freqs.searchsorted(maxfreq)
    if lastfreq > len(freqs):
        lastfreq = len(freqs)-1

Pxx = np.flipud(Pxx) #flipping image in the y-axis

interp='nearest'
seismic = plt.get_cmap('seismic')
cmap=seismic
fig = plt.figure()
ax1=fig.add_subplot(111)
extent = 0,4,freqs[0],freqs[lastfreq] # new extent
#plot reduced range
img1=ax1.imshow(Pxx[-lastfreq:], interpolation=interp, aspect='auto',
                extent=extent ,cmap=cmap)
ax1.set_autoscaley_on(False)
fig.colorbar(img1)
plt.show()

我的例子只设置了一个最大频率,不过稍微改动一下,你也可以设置一个最小频率。

撰写回答