Install
openclaw skills install plotEnhanced spectrogram visualization tools for time-frequency analysis. Use when creating spectrograms, spectral analysis, or time-frequency plots for signals including IMU data (accelerometer, gyroscope), physiological signals (PPG, ECG, respiration), vibration analysis, and audio processing. Supports frequency unit conversion (Hz/bpm/kHz), multiple normalization modes (global/local/none), and MATLAB-style parula colormap.
openclaw skills install plotEnhanced spectrogram visualization tools for professional time-frequency analysis.
import matplotlib.pyplot as plt
from pywayne.plot import regist_projection, parula_map
import numpy as np
# Register custom projection
regist_projection()
# Create spectrogram
fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'})
spec, freqs, t, im = ax.specgram(
x=signal_data,
Fs=100,
NFFT=128,
noverlap=96,
cmap=parula_map,
scale='dB'
)
ax.set_ylabel('Frequency (Hz)')
plt.colorbar(im, label='Magnitude (dB)')
plt.show()
Register the custom SpecgramAxes projection. Must be called before using the enhanced specgram functionality.
from pywayne.plot import regist_projection
regist_projection()
Enhanced spectrogram with advanced features.
Key Parameters:
| Parameter | Description | Default |
|---|---|---|
NFFT | FFT window length (points) | 256 |
Fs | Sampling frequency (Hz) | 2 |
noverlap | Overlap points between windows | 128 |
cmap | Colormap (use parula_map) | - |
mode | 'psd', 'magnitude', 'angle', 'phase' | 'psd' |
scale | 'dB' or 'linear' | 'dB' |
normalize | 'global', 'local', 'none' | 'global' |
freq_scale | Frequency scaling factor | 1.0 |
Fc | Center frequency offset (Hz) | 0 |
Returns:
spec - 2D spectrogram array (n_freqs, n_times)freqs - Frequency axis arrayt - Time axis arrayim - matplotlib image object (for colorbar)Auto-recommend STFT parameters based on signal characteristics.
from pywayne.plot import get_specgram_params
params = get_specgram_params(
signal_length=10000,
sampling_rate=100,
time_resolution=0.1 # or freq_resolution=0.5
)
# Returns: NFFT, noverlap, actual_freq_res, actual_time_res, n_segments
MATLAB-style perceptually uniform colormap for scientific visualization.
from pywayne.plot import parula_map
plt.imshow(data, cmap=parula_map)
fs = 100 # Sampling rate
win_time, step_time = 1, 0.1
fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'})
spec, freqs, t, im = ax.specgram(
x=acc_data,
Fs=fs,
NFFT=int(win_time * fs),
noverlap=int((win_time - step_time) * fs),
scale='dB',
cmap=parula_map
)
ax.set_ylabel('Frequency (Hz)')
ax.set_ylim(0, 30)
# Convert Hz to bpm for heart rate visualization
fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'})
spec, freqs, t, im = ax.specgram(
x=ppg_signal,
Fs=100,
NFFT=400,
noverlap=300,
freq_scale=60, # Hz -> bpm
scale='dB'
)
ax.set_ylabel('Heart Rate (bpm)')
ax.set_ylim(40, 180)
fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'})
spec, freqs, t, im = ax.specgram(
x=vibration_data,
Fs=1000,
NFFT=1024,
noverlap=512,
scale='linear',
normalize='global'
)
plt.colorbar(im, label='Normalized Magnitude')
fig, ax = plt.subplots(subplot_kw={'projection': 'z_norm'})
spec, freqs, t, im = ax.specgram(
x=signal,
Fs=100,
NFFT=100,
pad_to=512, # Zero-pad for smoother spectrum
noverlap=80,
scale='dB'
)
| Mode | Description | Use Case |
|---|---|---|
dB | Logarithmic (10log10 for PSD, 20log10 for magnitude) | Large dynamic range signals |
linear | Linear amplitude | Direct amplitude comparison |
scale='linear')| Mode | Description | Use Case |
|---|---|---|
global | Z/max(Z), preserves relative intensity | Compare intensity across time |
local | Per-column normalization to [0,1] | Focus on frequency content over time |
none | No normalization | Raw spectrogram values |
| freq_scale | Unit | Use Case |
|---|---|---|
| 1.0 | Hz | Default, most signals |
| 60 | bpm | Heart rate, respiration rate |
| 0.001 | kHz | Audio signals |
Example: freq_scale=60 converts 2 Hz → 120 bpm
Use get_specgram_params() to auto-calculate optimal parameters.
spec, freqs, t, im = ax.specgram(...)
def on_click(event):
if event.xdata and event.inaxes == ax:
time_idx = np.argmin(np.abs(t - event.xdata))
plt.figure()
plt.plot(freqs, spec[:, time_idx])
plt.title(f'FFT at t={event.xdata:.2f}s')
plt.show()
fig.canvas.mpl_connect('button_press_event', on_click)
regist_projection() before using projection='z_norm'parula_map is recommended for best perceptual uniformity