简体   繁体   中英

how to scale colorbar based on ylim

I am plotting a spectrogram of my data using matplotlib's specgram function.

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)

For ref, the shape of "freqs", "bins" (ie times) and "Pxx" above are (1025,), (45510,) and (1025,45510) respectively.

where, I have defined the function parameters

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

The frequency range (yaxis) for this plot is from 0 to 5E6 Hz. When I plot it, I am interested in viewing different frequency ranges, for example 100E3 Hz to 1E6. If I change the ylim of the plot, the colorbar limits don't change ie don't update to reflect the signal values in this "new" frequency range. Is there a way that I can do this, so that by changing the y-axis range plotted ie the frequency range limits , the colorbar will update/change accordingly?

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

I thought that if I could somehow find what the maximum and minimum value of Pxx was for the upper and lower frequencies respectively in the frequency range of interest, that I could use these values to set the colorbar limit eg

img1.set_clim(min_val, max_val) 

I can find the max and min values of Pxx in general and return their indices using

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

How do I go about finding the values of Pxx that correspond to the freq range of interest?

I can do something like the following to roughly find where for example in "freqs" 100E3 and 1E6 are approx. located using (and take the first (or last) value from each )...

   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]

OR

   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]

Then possibly

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

and finally

img1.set_clim(min_val, max_val)

Unfortunately this doesn't appear to be working in the sense that value range on the colorbar doesn't look correct. There must be a better/easier/more accurate way to do the above.

Instead of changing the limits in the graph, a possible solution is to change the data you plot and let colorbar do its thing. A minimal working example in the pylab environment:

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

My example only sets a maximum frequency, but with some small tweaks you can set a minimum.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM