Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default scaling of x-axis in specgram() is incorrect (i.e. the default value for the xextent parameter) #7666

Closed
DietBru opened this issue Dec 22, 2016 · 3 comments
Milestone

Comments

@DietBru
Copy link
Contributor

DietBru commented Dec 22, 2016

When drawing a spectrogram with the matplotlib.pyplot.specgram(), there's a systematic error when using the default value xextent=None, .i.e., xextent=(0, max(bins). Since the x-position is always the center an not the left of the FFT-window, the correct value is xextent=(min(bins), max(bins)).
The consequences can be demonstrated, when plotting the spectrogram of a linear chirp signal. This is the default behavior:
spec_default

This is is the desired behavior:
spec_correct

Those two images were generated by the following code::

import numpy as np
import sympy as sy
import matplotlib.pyplot as plt


t_sy = sy.Symbol("t", real=True)
fi_sy = 2 + 2*t_sy  # instantanenous frequency
phi_sy = fi_sy.integrate(t_sy) # instantaneous

fi_np = sy.lambdify(t_sy, fi_sy)  # numpy functions
phi_np = sy.lambdify(t_sy, phi_sy)
lb_fi = "$f_i(t)=%s$" % sy.latex(fi_sy)  # plot label

n_x = 2**10
T_x = 10/n_x
t_x = np.arange(n_x)*T_x

x = np.sin(2*np.pi*phi_np(t_x))  # generate signals
f_Xos, Xos = np.fft.rfftfreq(n_x*2, T_x), np.fft.rfft(x, n=2*n_x)

# Parameter for specgram:
nfft = 256 # Parameter NFFT
sargs = dict(x=2/nfft * x, NFFT=nfft, Fs=1/T_x, noverlap=nfft-1,
                   mode="magnitude", scale="linear", cmap=plt.cm.viridis)
fg1, ax1 = plt.subplots(1, 1)
fg2, ax2 = plt.subplots(1, 1)
ax1.set_title(r"256 Point Spectrogram with default 'xextent' parameter")
_, _, t_s1, im1 = ax1.specgram(**sargs)
ax2.set_title(r"256 Point Spectrogram with correct 'xextent' parameter")
_, _, t_s2, im2 = ax2.specgram(**sargs, xextent=(t_s1[0], t_s1[-1]))

for fg, ax, im in [(fg1, ax1, im1), (fg2, ax2, im2)]:
    ax.plot(t_x, fi_np(t_x), "r--", label=lb_fi, linewidth=.5)
    cb = fg.colorbar(im)
    cb.set_label("Magnitude $|X(t,f)|$")
    ax.legend()
    ax.set_xlim(t_x[0], t_x[-1])
    ax.set_xlabel(r"Time $t$ in Seconds ($\Delta t = %.3f\,$s)" % t_x[1])
    ax.set_ylabel(r"Frequency $f$ in Hertz ($\Delta f = %.3f\,$Hz)" % f_Xos[1])

plt.show()

Version Information:
Matplotlib 2.0.0rc2
Python 3.5.2 | packaged by conda-forge | (default, Sep 8 2016, 14:23:11)
[GCC 4.8.2 20140120 (Red Hat 4.8.2-15)] on linux

Thanks.

@tacaswell tacaswell added this to the 2.0.1 (next bug fix release) milestone Dec 22, 2016
@tacaswell
Copy link
Member

@vollbier Can you put in a PR to fix that?

@DietBru
Copy link
Contributor Author

DietBru commented Dec 22, 2016

Will do that over the christmas holidays.

QuLogic added a commit that referenced this issue Dec 29, 2016
Corrected default values of xextent in specgram(). Fixes Bug #7666.
@Kojoley
Copy link
Member

Kojoley commented Dec 31, 2016

Fixed with #7692.

@Kojoley Kojoley closed this as completed Dec 31, 2016
@tacaswell tacaswell modified the milestones: 2.1 (next point release), 2.0.1 (next bug fix release), 2.0 (style change major release) Dec 31, 2016
tacaswell pushed a commit that referenced this issue Jan 2, 2017
Corrected default values of xextent in specgram(). Fixes Bug #7666.

Conflicts:
	lib/matplotlib/axes/_axes.py
	   kept backported version, overlapping changes do to other cleanups
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants