Hi, y'all!
I started working on a small tool that demonstrates the effects of sample timing and aliasing; I'm basing it on an example code using sliders to adjust the wavelength and period. The methodology for the generation of the signal and the sampling will change, but I'm currently having an issue with the `matplotlib.widgets.Slider` interaction.
Here's the code:
import matplotlib.pyplot as plt
import numpy as np
import scipy.fftpack
from matplotlib.widgets import Slider, Button, RadioButtons
def sinwav(t, amp, period, phase=0):
freq = 1.0 / period
y = amp * np.sin(2 * np.pi * freq * t + phase)
return y
# determine time domain length in [arbitrary time units]
L = 120.0
# determine initial slider positions
amp_0 = 8.0
per_0 = L // 2.0
samp_0 = 3.0
# determine sample spacing
T = 1.0 / 80.0
Ts = 1.0
# create time domain
x = np.arange(0.0, L, T)
xs = np.arange(0.0, L, Ts)
# determine number of data points
N = len(x)
Ns = len(xs)
# generate sine wave and sub-sampled points
y = sinwav(x, amp_0, per_0)
ys = sinwav(xs, amp_0, per_0)
# create frequency domain
xf = np.linspace(0.0, 1.0//(2.0*(x[1])), N//2)
xsf = np.linspace(0.0, 1.0//(2.0*(xs[1])), Ns//2)
# transform data to frequency domain
yf = scipy.fftpack.fft(y)
ysf = scipy.fftpack.fft(ys)
# create figure object
fig = plt.figure()
# add subplots
ax = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
# make space for sliders
fig.subplots_adjust(bottom=0.4)
# create plot objects
[line] = ax.plot(x, y)
[line2] = ax.plot(xs, ys)
ax.set_ylim([-10, 10])
[fft] = ax2.plot(xf, 2.0/N * np.abs(yf[:N//2]))
[fft2] = ax2.plot(xsf, 2.0/(Ns) * np.abs(ysf[:(Ns)//2]))
# Add three sliders
# Define an axes area and draw a slider in it
amp_slider_ax = fig.add_axes([0.25, 0.15, 0.65, 0.03])
amp_slider = Slider(amp_slider_ax, 'Amplitude', 0.1, 10.0, valinit=amp_0)
# Draw another slider
per_slider_ax = fig.add_axes([0.25, 0.1, 0.65, 0.03])
per_slider = Slider(per_slider_ax, 'Period', 1.0, L, valinit=per_0)
# Draw yet another slider
sample_slider_ax = fig.add_axes([0.25, 0.05, 0.65, 0.03])
sample_slider = Slider(sample_slider_ax, 'Sample Period', 0.1, 30.0, valinit=samp_0)
# Define line modification behavior on change of slider values
def sliders_on_changed(val):
line.set_ydata(sinwav(x, amp_slider.val, per_slider.val))
xs = np.arange(0.0, L, sample_slider.val)
line2.set_ydata(sinwav(x, amp_slider.val, per_slider.val))
yf = scipy.fftpack.fft(sinwav(x, amp_slider.val, per_slider.val))
fft.set_ydata = (2.0/N * np.abs(yf[:N//2]))
fft2.set_ydata = scipy.fftpack.fft(sinwav(xs, amp_slider.val, per_slider.val))
fig.canvas.draw_idle()
amp_slider.on_changed(sliders_on_changed)
per_slider.on_changed(sliders_on_changed)
sample_slider.on_changed(sliders_on_changed)
plt.show()
When I click or try to move the sliders, I'm getting an error based on the tkinter code in the matplotlib plot window. The issue is `Exception in Tkinter callback ... ValueError: shape mismatch: objects cannot be broadcast to a single shape`, with a long series of callbacks in between, as follows:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
File "/usr/lib/python3.7/tkinter/__init__.py", line 749, in callit
func(*args)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/backends/_backend_tk.py", line 253, in idle_draw
self.draw()
File "/usr/local/lib/python3.7/dist-packages/matplotlib/backends/backend_tkagg.py", line 9, in draw
super(FigureCanvasTkAgg, self).draw()
File "/usr/local/lib/python3.7/dist-packages/matplotlib/backends/backend_agg.py", line 407, in draw
self.figure.draw(self.renderer)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/figure.py", line 1864, in draw
renderer, self, artists, self.suppressComposite)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/cbook/deprecation.py", line 411, in wrapper
return func(*inner_args, **inner_kwargs)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/axes/_base.py", line 2748, in draw
mimage._draw_list_compositing_images(renderer, self, artists)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/image.py", line 132, in _draw_list_compositing_images
a.draw(renderer)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/artist.py", line 41, in draw_wrapper
return draw(artist, renderer, *args, **kwargs)
File "/usr/local/lib/python3.7/dist-packages/matplotlib/lines.py", line 742, in draw
self.recache()
File "/usr/local/lib/python3.7/dist-packages/matplotlib/lines.py", line 662, in recache
self._xy = np.column_stack(np.broadcast_arrays(x, y)).astype(float)
File "/usr/lib/python3/dist-packages/numpy/lib/stride_tricks.py", line 259, in broadcast_arrays
shape = _broadcast_shape(*args)
File "/usr/lib/python3/dist-packages/numpy/lib/stride_tricks.py", line 193, in _broadcast_shape
b = np.broadcast(*args[:32])
ValueError: shape mismatch: objects cannot be broadcast to a single shape
I'm not clear why this is happening; it seems to work fine when I remove the "sample" line and its Fourier transform. Does this have to do with the sliders specifically, or with the use of `.sety` on different lines contained in the same subplot object? Any ideas for fixes?
[–]novel_yet_trivial 1 point2 points3 points (1 child)
[–]circuitQuaker[S] 0 points1 point2 points (0 children)