"""
Matplotlib plotting functions.
Convenience wrappers around common matplotlib pyplot plot calls. This module
simplifies the creation of filter frequency response curves and general
signal plots over time.
"""
from __future__ import print_function, division
import matplotlib.pyplot as plt
import numpy as np
import sensormotion.signal
from scipy.signal import freqz
[docs]def plot_filter_response(
frequency,
sample_rate,
filter_type,
filter_order=2,
show_grid=True,
fig_size=(10, 5),
):
"""Plot filter frequency response.
Generate a plot showing the frequency response curve of a filter with the
specified parameters.
Parameters
----------
frequency : int or tuple of ints
The cutoff frequency for the filter. If `filter_type` is set as
'bandpass' then this needs to be a tuple of integers representing
the lower and upper bound frequencies. For example, for a bandpass
filter with range of 2Hz and 10Hz, you would pass in the tuple (2, 10).
For filter types with a single cutoff frequency then a single integer
should be used.
sample_rate : float
Sampling rate of the signal.
filter_type : {'lowpass', 'highpass', 'bandpass', 'bandstop'}
Type of filter to build.
filter_order: int, optional
Order of the filter.
show_grid : bool, optional
Toggle to show grid lines on the plot.
fig_size : tuple, optional
Tuple containing the width and height of the resulting figure.
"""
b, a = sensormotion.signal.build_filter(
frequency, sample_rate, filter_type, filter_order
)
# Plot the frequency response
w, h = freqz(b, a, worN=8000)
f, axarr = plt.subplots(figsize=fig_size)
axarr.plot(0.5 * sample_rate * w / np.pi, np.abs(h), "b")
axarr.set_xlim(0, 0.5 * sample_rate)
axarr.set_xlabel("Frequency (Hz)")
axarr.grid(show_grid)
# Add lines and markers at the cutoff frequency/frequencies
if filter_type == "bandpass":
for i in range(len(frequency)):
axarr.axvline(frequency[i], color="k")
axarr.plot(frequency[i], 0.5 * np.sqrt(2), "ko")
else:
axarr.axvline(frequency, color="k")
axarr.plot(frequency, 0.5 * np.sqrt(2), "ko")
plt.suptitle("Filter Frequency Response", size=16)
plt.show()
[docs]def plot_signal(
time,
signal,
title="",
xlab="",
ylab="",
line_width=1,
alpha=1,
color="k",
subplots=False,
show_grid=True,
fig_size=(10, 5),
):
"""Plot signals over time.
Convenience wrapper around pyplot to quickly create plots of signals
over time. This is useful if you want to avoid remembering the syntax
for matplotlib.
Parameters
----------
time : ndarray
Time vector of the signal (X-axis)
signal : ndarray or list of dicts
If plotting a single line, you can pass in a single array.
If you want to plot multiple lines (either on the same plot, or as
subplots) you should pass in a list of dictionaries. Each dictionary
represents a separate line and contains options for that line. The
dictionary can hold the follow keys: 'data' (required), 'label',
'color', 'alpha', 'line_width'.
For example, a 2 line plot can be created like this:
>>> plot.plot_signal(time_array, [{'data': line1_data,
'label': 'line 1',
'color': 'b'},
{'data': line2_data,
'label': 'second line',
'line_Width': 4}])
title : str, optional
Title of the plot.
xlab : str, optional
Label for the x axis.
ylab : str, optional
Label for the y axis.
line_width : int or float, optional
Width of the plot lines.
alpha : int or float, optional
Alpha of the plot lines.
color : str, optional
Colour of the plot lines. Receives a string following the matplotlib
colors API: http://matplotlib.org/api/colors_api.html
subplots : bool, optional
If multiple lines are passed in, should they be displayed on the same
plot (False)? Or should each be displayed in separate subplots (True)?
show_grid : bool, optional
Toggle to display grid lines on the plot.
fig_size : tuple, optional
Set the figure size of the resulting plot.
"""
if type(signal) == list: # Multiple lines to be plotted
if subplots:
f, axarr = plt.subplots(len(signal), 1, figsize=fig_size)
else:
f, axarr = plt.subplots(figsize=fig_size)
for i, line in enumerate(signal): # Iterate through each plot line
cur_data = line["data"]
# Get options for the current line
try:
cur_label = line["label"]
except KeyError:
print("Warning: Label missing for signal")
cur_label = ""
try:
cur_color = line["color"]
except KeyError:
cur_color = color
try:
cur_alpha = line["alpha"]
except KeyError:
cur_alpha = alpha
try:
cur_linewidth = line["line_width"]
except KeyError:
cur_linewidth = line_width
if subplots: # Show lines in separate plots, in the same figure
axarr[i].plot(
time,
cur_data,
label=cur_label,
linewidth=cur_linewidth,
alpha=cur_alpha,
color=cur_color,
)
axarr[i].set_xlim(min(time), max(time))
axarr[i].set_xlabel(xlab)
axarr[i].set_ylabel(ylab)
axarr[i].grid(show_grid)
axarr[i].legend()
f.subplots_adjust(hspace=0.5)
else: # Show all lines on the same plot
axarr.plot(
time,
cur_data,
label=cur_label,
linewidth=cur_linewidth,
alpha=cur_alpha,
color=cur_color,
)
axarr.set_xlim(min(time), max(time))
axarr.set_xlabel(xlab)
axarr.set_ylabel(ylab)
axarr.grid(show_grid)
axarr.legend()
else: # Single line plot
f, axarr = plt.subplots(figsize=fig_size)
axarr.plot(time, signal, linewidth=line_width, alpha=alpha, color=color)
axarr.set_xlim(min(time), max(time))
axarr.set_xlabel(xlab)
axarr.set_ylabel(ylab)
axarr.grid(show_grid)
plt.suptitle(title, size=16)
plt.show()