# Why does a signal with constant frequency have spots that changes colors at a specific value of scale (and so frequency) in the scalogram?

I am studying the Wavelet transform and I am considering this example that I took from PyWavelets documentation. The signal in time domain has the following shape:

Till the value of zero on the horizontal axis we have a signal with a constant frequency. So I would expect the scalogram to have something like a constant (both in color and in dimension) horizontal stripe at a specific value of the scale (or period or frequency or whatever you want to put on the y axis of the scalogram) till the zero value, while instead it has like vertical stripes that alternate their colors from the extreme violet color to the extreme green. Why ?! This is the image:

From a scalogram like this, I would expect a signal that changes frequencies because the changing of colors means that changing of values of wavelets coefficients and so the changing of similarity between the wavelet and the input signal (since the operation that is done is the convolution between the wavelet and the data). High similarity should mean high coefficients (so green color) while low similarity means low values of coefficients (so violet colors); if the colors changes means that the similarity changes and so also the shape of the signal changes and thus also the frequency. Is this right ? What am I missing ?

Any suggestion would be really appreciated. Thanks in advance.

EDITI:I appreciate the suggestions in the comments below my post but since there has not been an answer to my post and my question has not been closed, I want to share with you that I found a clear explanation in this nice video Wavelets: a mathematical microscope. As Ash pointed out, one should plot the magnitude of a complex wavelet and so one has to consider the convolution with both the real and imaginary part of the wavelet. Hence by following this procedure, I obtain the plot as I expected it to be but with still one problem: the red bar that should be in correspondence of scale value equal to 30 and the distortions (that correspond to signal changing in frequency) should go from 30 to lower scales, in my case is inverted. Why ?

Here is the Python code that I used:

time = np.linspace(-1, 1, 200, endpoint=False)
signal  = np.cos(2 * np.pi * 7 * time) + np.real(np.exp(-7*(time-0.4)**2)*np.exp(1j*2*np.pi*2*(time-0.4)))

fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(time,signal)
sns.despine(fig, bottom=False, left=False)
plt.show()

scales = np.arange(1,31)
ylabel = 'Period'
xlabel = 'Time'

waveletname='cgau2'
coef, freqs=pywt.cwt(signal, scales, waveletname)

fig, ax = plt.subplots(figsize=(12, 2))
contourf_ = ax.contourf(time, scales, np.abs(coef), cmap=plt.cm.Reds)#extend='both',
ax.set_title('Wavelet Transform of Signal ($${}$$)'.format(waveletname), fontsize=20)
ax.set_ylabel('Scales', fontsize=14)
ax.set_xlabel('Time (s)', fontsize=14)
fig.colorbar(contourf_)
plt.show()



EDITII:

#Time domain signal
time = np.linspace(-1, 1, 200, endpoint=False)
signal  = np.cos(2 * np.pi * 7 * time) + np.real(np.exp(-7*(time-0.4)**2)*np.exp(1j*2*np.pi*2*(time-0.4)))

fig, ax = plt.subplots(figsize=(9, 5))
ax.plot(time,signal)
sns.despine(fig, bottom=False, left=False)
plt.show()

#Setting parameters for Continous Wavelet Transform
scales = np.arange(1,31)
waveletname='cgau2'
coef, freqs=pywt.cwt(signal, scales, waveletname)

#contourf

fig, ax = plt.subplots(figsize=(12, 2))
contourf_ = ax.contourf(time, scales, np.abs(coef), cmap=plt.cm.Reds)#extend='both',
ax.set_title('Wavelet Transform of Signal ($${}$$)'.format(waveletname), fontsize=20)
ax.set_ylabel('Scales', fontsize=14)
ax.set_xlabel('Time (s)', fontsize=14)
fig.colorbar(contourf_)
plt.show()

#matshow
fig, ax = plt.subplots(figsize=(12, 5))
matshow_ = ax.matshow(np.abs(coef), extent=[-1, 1, 1, 31], aspect = 'auto', cmap='Reds',
vmax=abs(coef).max(), vmin=0)
fig.colorbar(matshow_)
plt.gca().xaxis.tick_bottom() # it puts x axis from top to bottom of figure.
loc = plticker.MultipleLocator(base=0.25)  # this locator puts ticks at regular intervals
ax.xaxis.set_major_locator(loc)
ax.set_title('Wavelet Transform of Signal ($${}$$)'.format(waveletname), fontsize=20)
ax.set_ylabel('Scales', fontsize=15)
ax.set_xlabel('Time', fontsize=15)
plt.show()

#imshow
fig, ax = plt.subplots(figsize=(12, 5))
imshow_ = plt.imshow(np.abs(coef), extent=[-1, 1, 1, 31], cmap='Reds', aspect='auto',
vmax=abs(coef).max(), vmin=0)
fig.colorbar(imshow_)
ax.set_title('Wavelet Transform of Signal ($${}$$)'.format(waveletname), fontsize=20)
ax.set_ylabel('Scales', fontsize=15)
ax.set_xlabel('Time', fontsize=15)
plt.show()



This is the plot using matshow or imshow.

• Try plotting the magnitude instead of just the real or imaginary part.
– Ash
Commented Nov 28, 2022 at 19:47
• Ash is correct, I also recommend against pywt in favor of ssqueezepy, though I'm the author. This specific example is fine in pywt. Commented Nov 29, 2022 at 12:42
• @Ash I edited the post. I followed your advice but I have still problems... If you can give further hints please :)
– User
Commented Dec 4, 2022 at 7:57

### Re: real part

There are oscillations because that's what the wavelet transform is - a decomposition into zero-mean, localized oscillations. CWT is convolution (rather, cross-correlation) of signal with wavelets, and you're taking the real part of this result: top animation here may help. With analytic or real wavelets, the CWT also nicely interprets as "redistributing" the signal over a 2D plane, with each oscillatory component in its proper slot, per the one-integral inverse.

abs gives intensity, which interprets as amplitude but only with analytic wavelets, which cgau2 isn't, and is why b is over-represented.

### Re: wrong scales

The red plot is correct, the green-purple one isn't. Lower scale $$\Leftrightarrow$$ higher frequency. Let's plot sig:

• Blue is a pure sine: constant frequency over time, so a horizontal bar in time-freq
• Orange is a Gaussian-windowed sine: constant frequency but localized in time, so a "lump" in time-freq

Clearly, orange is lower in frequency, hence "resonates" with greater scale. pywt's example is fixed via extent=[-1, 1, 31, 1] (I originally ignored this). For best results, apply a wavelet with high time resolution:

Note the sine is around frequency=7, matching np.cos(2 * np.pi * 7 * t).

import numpy as np
from ssqueezepy import cwt, Wavelet
from ssqueezepy.experimental import scale_to_freq
from ssqueezepy.visuals import imshow

t = np.linspace(-1, 1, 200, endpoint=False)
sig = (np.cos(2 * np.pi * 7 * t) +
np.real(np.exp(-7*(t-0.4)**2)*np.exp(1j*2*np.pi*2*(t-0.4))))

wavelet = Wavelet(('gmw', {'beta': 4}))
Wx, scales = cwt(sig, wavelet, padtype='zero')

freqs = scale_to_freq(scales, wavelet, N=len(sig), fs=1/(t[1] - t[0]))
imshow(Wx, abs=1, yticks=freqs,  xticks=t,
xlabel="time [sec]", ylabel="frequency [Hz]")

• Thanks for your answer ! Your module is really powerfull and intuitive. One question related to this: how to know the list of wavelets available with ssqueezepy ? And lastly, (which was in truth the original question), why by using contourf the resulting image is opposite to what it should be ?
– User
Commented Dec 5, 2022 at 7:38
• @User ssqueezepy.wavs(), code in wavelets.py. Also worth noting ssqueezepy.Wavelet().info(). To your question, again, the red image is correct; the green-purple one is incorrect because the y-axis is scales and yet a ends up at a higher scale than b. Commented Dec 5, 2022 at 7:46
• Ok I discovered that it was because of extent... removing it, all results are the same as your plot. Thank you very much !
– User
Commented Dec 5, 2022 at 11:33
• @User Valid question concerning real part, updated. Also note scales in contourf flips the plot. Commented Dec 5, 2022 at 11:35
• @User No problem, I appreciate your well-researched question. I'll try to get around to it. Commented Mar 3, 2023 at 11:21