specplotter 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 UT SALT Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,509 @@
1
+ Metadata-Version: 2.4
2
+ Name: specplotter
3
+ Version: 1.1.0
4
+ Summary: A tool for creating wideband spectrograms with signal analysis
5
+ Author-email: Your Name <your.email@example.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/juice500ml/specplotter
8
+ Project-URL: Documentation, https://github.com/juice500ml/specplotter#readme
9
+ Project-URL: Repository, https://github.com/juice500ml/specplotter
10
+ Project-URL: Issues, https://github.com/juice500ml/specplotter/issues
11
+ Keywords: spectrogram,audio,signal-processing,librosa,scipy
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.7
17
+ Classifier: Programming Language :: Python :: 3.8
18
+ Classifier: Programming Language :: Python :: 3.9
19
+ Classifier: Programming Language :: Python :: 3.10
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Requires-Python: >=3.7
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.19.0
26
+ Requires-Dist: scipy>=1.5.0
27
+ Requires-Dist: librosa>=0.8.0
28
+ Requires-Dist: matplotlib>=3.3.0
29
+ Provides-Extra: dev
30
+ Requires-Dist: pytest>=6.0; extra == "dev"
31
+ Requires-Dist: ruff; extra == "dev"
32
+ Requires-Dist: pre-commit; extra == "dev"
33
+ Requires-Dist: python-semantic-release[build]; extra == "dev"
34
+ Dynamic: license-file
35
+
36
+ # SpecPlotter
37
+
38
+ A Python package for creating wideband and narrowband spectrograms with comprehensive signal analysis features.
39
+
40
+ ## Features
41
+
42
+ - **Wideband and narrowband spectrogram generation** - Switch between analysis modes
43
+ - **Modular signal processing** - Compute individual features independently
44
+ - **Flexible plotting** - Choose which components to display
45
+ - **Zero crossing rate analysis** - Optional ZCR visualization
46
+ - **Energy analysis** - Total energy and low-frequency energy calculations
47
+ - **Waveform visualization** - Optional waveform display
48
+ - **Fully configurable** - All parameters are customizable
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install specplotter
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ### Command Line Interface
59
+
60
+ The easiest way to use SpecPlotter is via the command line:
61
+
62
+ ```bash
63
+ # Basic spectrogram (PNG)
64
+ specplotter audio.wav -o output.png
65
+
66
+ # Basic spectrogram (PDF)
67
+ specplotter audio.wav -o output.pdf
68
+
69
+ # Full analysis with all components
70
+ specplotter audio.wav -o output.pdf --zcr --total-energy --lowfreq-energy --waveform
71
+
72
+ # Narrowband mode
73
+ specplotter audio.wav -o output.png --mode narrowband
74
+ ```
75
+
76
+ ### Python API
77
+
78
+ ```python
79
+ from specplotter import SpecPlotter
80
+ import librosa
81
+
82
+ # Load an audio file
83
+ signal, sr = librosa.load('audio.wav', sr=16000)
84
+
85
+ # Create a SpecPlotter instance (default: wideband mode)
86
+ plotter = SpecPlotter()
87
+
88
+ # Plot spectrogram only (default behavior)
89
+ plotter.plot_spectrogram(signal)
90
+
91
+ # Or save to file
92
+ plotter.plot_spectrogram(signal, outfile='spectrogram.png')
93
+ ```
94
+
95
+ ## Usage Examples
96
+
97
+ ### Basic Usage
98
+
99
+ ```python
100
+ from specplotter import SpecPlotter
101
+ import librosa
102
+
103
+ signal, sr = librosa.load('audio.wav', sr=16000)
104
+ plotter = SpecPlotter()
105
+
106
+ # Default: spectrogram only
107
+ plotter.plot_spectrogram(signal)
108
+ ```
109
+
110
+ ### Wideband vs Narrowband
111
+
112
+ ```python
113
+ # Wideband mode (default)
114
+ plotter_wide = SpecPlotter(mode='wideband')
115
+
116
+ # Narrowband mode
117
+ plotter_narrow = SpecPlotter(mode='narrowband')
118
+
119
+ # Plot with different modes
120
+ plotter_wide.plot_spectrogram(signal)
121
+ plotter_narrow.plot_spectrogram(signal)
122
+ ```
123
+
124
+ ### Flexible Plotting with Optional Components
125
+
126
+ ```python
127
+ # Plot with all components
128
+ plotter.plot(
129
+ signal,
130
+ show_zcr=True,
131
+ show_total_energy=True,
132
+ show_lowfreq_energy=True,
133
+ show_waveform=True
134
+ )
135
+
136
+ # Just spectrogram and waveform
137
+ plotter.plot(signal, show_waveform=True)
138
+
139
+ # Spectrogram with zero crossing rate
140
+ plotter.plot(signal, show_zcr=True)
141
+ ```
142
+
143
+ ### Using Custom Axes
144
+
145
+ ```python
146
+ import matplotlib.pyplot as plt
147
+
148
+ # Single axis (spectrogram only)
149
+ fig, ax = plt.subplots()
150
+ plotter.plot_spectrogram(signal, ax=ax)
151
+
152
+ # List of axes matching number of plots
153
+ fig, axes = plt.subplots(3, 1) # For zcr, spectrogram, waveform
154
+ plotter.plot(
155
+ signal,
156
+ ax=list(axes),
157
+ show_zcr=True,
158
+ show_waveform=True
159
+ )
160
+
161
+ # Full plot with all components
162
+ fig, axes = plt.subplots(5, 1)
163
+ plotter.plot(
164
+ signal,
165
+ ax=list(axes),
166
+ show_zcr=True,
167
+ show_total_energy=True,
168
+ show_lowfreq_energy=True,
169
+ show_waveform=True
170
+ )
171
+ ```
172
+
173
+ **Note:** When providing a list of axes, they must be in this order:
174
+ 1. `zcr` (if `show_zcr=True`)
175
+ 2. `total_energy` (if `show_total_energy=True`)
176
+ 3. `lowfreq_energy` (if `show_lowfreq_energy=True`)
177
+ 4. `spectrogram` (always included)
178
+ 5. `waveform` (if `show_waveform=True`)
179
+
180
+ ### Computing Features Without Plotting
181
+
182
+ ```python
183
+ # Compute all features
184
+ features = plotter.compute_spectrogram(signal)
185
+
186
+ # Access individual features
187
+ processed_signal = features['processed_signal']
188
+ spectrogram = features['spectrogram']
189
+ zcr = features['zcr']
190
+ total_energy = features['total_energy']
191
+ lowfreq_energy = features['lowfreq_energy']
192
+
193
+ # Use features independently
194
+ import matplotlib.pyplot as plt
195
+ fig, ax = plt.subplots()
196
+ plotter._plot_spectrogram_on_axis(spectrogram, len(signal), ax=ax)
197
+ ```
198
+
199
+ ### Individual Plotting Methods
200
+
201
+ ```python
202
+ features = plotter.compute_spectrogram(signal)
203
+
204
+ # Plot individual components
205
+ fig, ax = plt.subplots()
206
+ plotter.plot_zcr(features['zcr'], ax=ax)
207
+
208
+ fig, ax = plt.subplots()
209
+ plotter.plot_total_energy(features['total_energy'], ax=ax)
210
+
211
+ fig, ax = plt.subplots()
212
+ plotter.plot_lowfreq_energy(features['lowfreq_energy'], ax=ax)
213
+
214
+ fig, ax = plt.subplots()
215
+ plotter.plot_waveform(features['processed_signal'], ax=ax)
216
+ ```
217
+
218
+ ## Configuration
219
+
220
+ ### Mode Selection
221
+
222
+ The `mode` parameter sets default window sizes for wideband or narrowband analysis:
223
+
224
+ - **Wideband** (default): `window_size=0.004`, `window_stride=0.001`
225
+ - **Narrowband**: `window_size=0.025`, `window_stride=0.01`
226
+
227
+ ### Customizing Parameters
228
+
229
+ All parameters can be customized when creating a SpecPlotter instance:
230
+
231
+ ```python
232
+ plotter = SpecPlotter(
233
+ mode='wideband', # 'wideband' or 'narrowband'
234
+ sample_rate=16000, # Sample rate (Hz)
235
+ fnotch=60, # Notch filter frequency (Hz)
236
+ notchQ=30, # Notch filter Q factor
237
+ preemphasis_coeff=0.97, # Pre-emphasis coefficient
238
+ window_size=0.004, # Window size (seconds), optional
239
+ window_stride=0.001, # Window stride (seconds), optional
240
+ n_fft=1024, # Number of FFT points
241
+ window=scipy.signal.windows.hamming, # Window function
242
+ db_spread=60, # Dynamic range (dB)
243
+ db_cutoff=3, # Minimum dB value
244
+ fig_height=10, # Figure height (inches)
245
+ inches_per_sec=10, # Horizontal scaling
246
+ zcr_smoothing_std=6, # ZCR smoothing std dev
247
+ zcr_smoothing_size=41, # ZCR smoothing kernel size
248
+ lowfreq_min=125, # Low freq energy min (Hz)
249
+ lowfreq_max=750, # Low freq energy max (Hz)
250
+ )
251
+ ```
252
+
253
+ ### Overriding Mode Defaults
254
+
255
+ You can override mode defaults by explicitly providing `window_size` and `window_stride`:
256
+
257
+ ```python
258
+ # Use wideband mode but with custom window settings
259
+ plotter = SpecPlotter(
260
+ mode='wideband',
261
+ window_size=0.005, # Override default
262
+ window_stride=0.002 # Override default
263
+ )
264
+ ```
265
+
266
+ ## Command Line Interface
267
+
268
+ SpecPlotter includes a command-line interface for quick spectrogram generation.
269
+
270
+ ### Basic Usage
271
+
272
+ ```bash
273
+ specplotter <input_file> -o <output_file>
274
+ ```
275
+
276
+ The output format (PNG or PDF) is automatically determined from the file extension.
277
+
278
+ ### Options
279
+
280
+ **Required:**
281
+ - `input_file`: Path to input WAV file
282
+ - `-o, --output`: Output file path (must have .png or .pdf extension)
283
+
284
+ **Analysis Mode:**
285
+ - `--mode {wideband,narrowband}`: Analysis mode (default: wideband)
286
+
287
+ **Additional Plots:**
288
+ - `--all`: Show all additional plots (zcr, total-energy, lowfreq-energy, waveform)
289
+ - `--zcr`: Show zero crossing rate plot
290
+ - `--total-energy`: Show total energy plot
291
+ - `--lowfreq-energy`: Show low frequency energy plot
292
+ - `--waveform`: Show waveform plot
293
+
294
+ **Audio Settings:**
295
+ - `--sample-rate FLOAT`: Sample rate in Hz (default: 16000)
296
+
297
+ **Processing Parameters:**
298
+ - `--fnotch FLOAT`: Notch filter frequency in Hz (default: 60)
299
+ - `--notch-q FLOAT`: Notch filter Q factor (default: 30)
300
+ - `--db-spread FLOAT`: Dynamic range in dB (default: 60)
301
+ - `--db-cutoff FLOAT`: Minimum dB value to display (default: 3)
302
+
303
+ ### Examples
304
+
305
+ ```bash
306
+ # Basic spectrogram
307
+ specplotter audio.wav -o spectrogram.png
308
+
309
+ # Full analysis (all components)
310
+ specplotter audio.wav -o analysis.pdf --all
311
+
312
+ # Narrowband mode with custom settings
313
+ specplotter audio.wav -o output.pdf --mode narrowband --db-spread 80
314
+
315
+ # Custom sample rate
316
+ specplotter audio.wav -o output.png --sample-rate 22050
317
+
318
+ # European line noise (50 Hz instead of 60 Hz)
319
+ specplotter audio.wav -o output.pdf --fnotch 50
320
+ ```
321
+
322
+ ### Help
323
+
324
+ For full help and all options:
325
+
326
+ ```bash
327
+ specplotter --help
328
+ ```
329
+
330
+ ## API Reference
331
+
332
+ ### `SpecPlotter.__init__()`
333
+
334
+ Initialize SpecPlotter with configurable parameters. See Configuration section above for all parameters.
335
+
336
+ ### `compute_spectrogram(signal)`
337
+
338
+ Compute spectrogram and related features.
339
+
340
+ **Parameters:**
341
+ - `signal` (np.ndarray): Input audio signal
342
+
343
+ **Returns:**
344
+ - `dict`: Dictionary containing:
345
+ - `'processed_signal'`: Preprocessed signal
346
+ - `'spectrogram'`: Clipped log spectrogram
347
+ - `'zcr'`: Zero crossing rate
348
+ - `'total_energy'`: Total energy envelope
349
+ - `'lowfreq_energy'`: Low frequency energy envelope
350
+
351
+ ### `plot(signal, ax=None, show_zcr=False, show_total_energy=False, show_lowfreq_energy=False, show_waveform=False, outfile=None, **kwargs)`
352
+
353
+ Plot spectrogram with optional additional features.
354
+
355
+ **Parameters:**
356
+ - `signal` (np.ndarray): Input audio signal
357
+ - `ax` (Axes or list of Axes, optional): Matplotlib axes to plot on
358
+ - `show_zcr` (bool): Whether to show zero crossing rate plot
359
+ - `show_total_energy` (bool): Whether to show total energy plot
360
+ - `show_lowfreq_energy` (bool): Whether to show low frequency energy plot
361
+ - `show_waveform` (bool): Whether to show waveform plot
362
+ - `outfile` (str, optional): If provided, save figure to file
363
+ - `**kwargs`: Additional keyword arguments passed to plotting functions
364
+
365
+ **Returns:**
366
+ - `tuple`: (figure, axes_dict)
367
+
368
+ ### `plot_spectrogram(signal, ax=None, outfile=None, **kwargs)`
369
+
370
+ Plot spectrogram only (convenience method).
371
+
372
+ **Parameters:**
373
+ - `signal` (np.ndarray): Input audio signal
374
+ - `ax` (Axes, optional): Matplotlib axes to plot on
375
+ - `outfile` (str, optional): If provided, save figure to file
376
+ - `**kwargs`: Additional keyword arguments
377
+
378
+ **Returns:**
379
+ - `tuple`: (figure, axes)
380
+
381
+ ## Requirements
382
+
383
+ - Python >= 3.7
384
+ - numpy >= 1.19.0
385
+ - scipy >= 1.5.0
386
+ - librosa >= 0.8.0
387
+ - matplotlib >= 3.3.0
388
+
389
+ ## License
390
+
391
+ MIT License
392
+
393
+ ## Versioning
394
+
395
+ This package uses [python-semantic-release](https://python-semantic-release.readthedocs.io/) for automatic version management based on [Conventional Commits](https://www.conventionalcommits.org/).
396
+
397
+ ### How it works
398
+
399
+ The version is automatically determined from your commit messages:
400
+ - `fix:` or `fix(scope):` → patch version bump (0.0.1 → 0.0.2)
401
+ - `feat:` or `feat(scope):` → minor version bump (0.0.1 → 0.1.0)
402
+ - `feat!:` or `fix!:` or `BREAKING CHANGE:` → major version bump (0.0.1 → 1.0.0)
403
+
404
+ ### Creating a new release
405
+
406
+ Simply push commits with conventional commit messages to the main branch:
407
+
408
+ ```bash
409
+ git commit -m "feat: add new spectrogram visualization feature"
410
+ git push origin main
411
+ ```
412
+
413
+ The GitHub Actions workflow will:
414
+ 1. Analyze your commits since the last release
415
+ 2. Determine the appropriate version bump
416
+ 3. Update version numbers in `pyproject.toml` and `__init__.py`
417
+ 4. Create a git tag
418
+ 5. Generate/update CHANGELOG.md
419
+ 6. Create a GitHub release
420
+ 7. Build and publish to PyPI (if `PYPI_API_TOKEN` is configured)
421
+
422
+ ### Commit message format
423
+
424
+ Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
425
+
426
+ ```
427
+ <type>[optional scope]: <description>
428
+
429
+ [optional body]
430
+
431
+ [optional footer(s)]
432
+ ```
433
+
434
+ **Types:**
435
+ - `feat`: A new feature
436
+ - `fix`: A bug fix
437
+ - `docs`: Documentation only changes
438
+ - `style`: Code style changes (formatting, etc.)
439
+ - `refactor`: Code refactoring
440
+ - `perf`: Performance improvements
441
+ - `test`: Adding or updating tests
442
+ - `chore`: Maintenance tasks
443
+
444
+ **Examples:**
445
+ ```bash
446
+ git commit -m "feat: add support for custom color maps"
447
+ git commit -m "fix: correct frequency calculation in spectrogram"
448
+ git commit -m "feat!: change API for plot_spectrogram method"
449
+ git commit -m "docs: update installation instructions"
450
+ ```
451
+
452
+ ## Testing
453
+
454
+ Run tests using pytest:
455
+
456
+ ```bash
457
+ # Install development dependencies
458
+ pip install -e ".[dev]"
459
+
460
+ # Run all tests
461
+ pytest
462
+
463
+ # Run with verbose output
464
+ pytest -v
465
+
466
+ # Run specific test file
467
+ pytest tests/test_specplotter.py
468
+ ```
469
+
470
+ The test suite includes:
471
+ - Unit tests for SpecPlotter initialization and configuration
472
+ - Tests for spectrogram computation
473
+ - Tests for plotting functionality
474
+ - Tests for CLI interface
475
+ - Tests for error handling
476
+
477
+ ## Contributing
478
+
479
+ Contributions are welcome! Please feel free to submit a Pull Request.
480
+
481
+ ### Setting up pre-commit hooks
482
+
483
+ This project uses pre-commit hooks to ensure code quality. To set them up:
484
+
485
+ ```bash
486
+ # Install pre-commit
487
+ pip install pre-commit
488
+
489
+ # Install the git hooks
490
+ pre-commit install
491
+
492
+ # Or run manually
493
+ pre-commit run --all-files
494
+ ```
495
+
496
+ The pre-commit hooks will automatically:
497
+ - Remove trailing whitespace
498
+ - Fix end-of-file issues
499
+ - Check YAML, JSON, and TOML syntax
500
+ - Format code with ruff
501
+ - Run ruff linting (with auto-fix)
502
+ - Check for merge conflicts
503
+
504
+ ### Before submitting
505
+
506
+ 1. Run the test suite: `pytest`
507
+ 2. Run pre-commit hooks: `pre-commit run --all-files`
508
+ 3. Ensure all tests pass
509
+ 4. Ensure code formatting is correct