# PyWavelets: twenty years of wavelet transforms in Python

> A numerical library built on Cython and NumPy, with a Python 3.12 floor, a meson build, and a licensing story the README does not tell on its own.

**PyWavelets/pywt** — PyWavelets - Wavelet Transforms in Python

- Repository: https://github.com/PyWavelets/pywt
- Website: http://pywavelets.readthedocs.org
- Stars: 2,407 · Forks: 542
- Language: Python
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/pywavelets-pywt

## From a 2006 medical thesis to a compiled extension

PyWavelets started in 2006 as an academic project for a master thesis on analysis and classification of medical signals using wavelet transforms, and its original developer maintained it until 2012. In 2013 maintenance moved to a new repository under a larger development team, with the original developer supporting the move. The README is careful about one point in that history, noting that the move does not make the new repository a fork: the package keeps the PyWavelets name and is still released on PyPI and GitHub.

Two details are worth sitting with if you care about provenance. GitHub reports the owner as the PyWavelets organization and the repository name as pywt, while the distribution name in the project metadata is PyWavelets and the import name is pywt. And the issue the README links as the place where the naming decision was discussed still lives under the older nigma/pywt path. The lineage therefore runs through an account name that tells you nothing about the current project, which is a small reminder that repository moves are normal and the old URLs tend to outlive the move.

The activity numbers fit a library that is mature rather than abandoned. GitHub reports 2,403 stars, 541 forks and 84 open issues, with the last push dated 2026-09-17. The language is recorded as Python and the default branch as main.

## What the feature list is actually promising

The README explains why wavelets exist by comparing them to Fourier transforms. Wavelets are mathematical basis functions localized in both time and frequency, whereas Fourier transforms are localized only in frequency. Everything else in the feature list follows from wanting that time localization while keeping the machinery of a transform.

The declared features cover a lot of ground. There is forward and inverse discrete wavelet transform in one, two and n dimensions, multilevel variants of the same, a stationary and undecimated transform in one and two dimensions, wavelet packet decomposition and reconstruction, a one dimensional continuous wavelet transform, and approximations of wavelet and scaling functions. There are over 100 built-in filters with support for custom wavelets, results compatible with the Matlab Wavelet Toolbox, and both single and double precision alongside real and complex arithmetic.

Read that last group as a performance and correctness choice rather than a feature bullet. When a library offers real and complex paths and single and double precision, the cheaper path is a decision you make about your data. A stack of float64 values against complex128 values is not a rounding detail at the scale most transforms run, so knowing which variant you are paying for is the practical skill here.

## The Python 3.12 floor and the bounded NumPy range

The README states that PyWavelets supports Python >=3.12 and depends only on NumPy, with supported versions currently >=2.0.0,<3. Matplotlib is also required if you want to pass all of the tests. The project metadata agrees exactly, declaring requires-python = ">=3.12" and dependencies = ["numpy>=2.0.0,<3"].

So the supported interpreter range is narrow by design rather than by neglect. The classifier list runs from Python 3.12 through 3.15 and includes a free threading classifier marked as beta, so the project is tracking current interpreter releases while declining anything older. If your environment is on an older interpreter, there is no workaround and no flag, because the constraint is a lower bound at the packaging level.

The NumPy bound is worth the same attention, because it is bounded at both ends. An upper bound below 3 means a future NumPy major release will not satisfy the constraint without a new PyWavelets release. That is deliberate packaging discipline and it means you should pin NumPy deliberately rather than letting an unrelated upgrade move it.

The README also warns that Linux distribution packages tend to be moderately out of date, naming the various package titles to try. That is a caution with a concrete check attached: run `python -c "import pywt; print(pywt.__version__, pywt.__file__)"` and compare both the version and the path against what you expected.

## Meson, Cython, and two CI systems

The build system is specified in the project metadata:

```
[build-system]
build-backend = "mesonpy"
requires = [
    "meson-python>=0.18.0",
    "Cython>=3.2.5",
    "numpy>=2.0.0,<3",
]
```

The repository tree confirms a meson build at the root alongside tox.ini, pytest.ini, a coverage configuration, a pre-commit configuration and a readthedocs configuration. There is also a .spin directory, a benchmarks directory, a util directory holding build helper scripts, and both CONTRIBUTING.rst and community_guidelines.rst. Anyone who has installed pywt from source will recognize the implication of the backend choice: this is a compiled extension, not a collection of pure Python modules.

The README tells source builders what that requires, stating that you need a working C compiler, any common one will work, and a recent version of Cython, then to navigate to the source directory containing pyproject.toml. The three supported install paths are short:

```
pip install PyWavelets
conda install -c conda-forge pywavelets
pip install .
```

Binary wheels exist for Intel Linux, Windows and macOS, so the compiled path is the exception rather than the default for most users.

One small inconsistency in the README is harmless but tells you how carefully to read it. The badge table at the top is headed Master branch, yet every badge URL and target link in that table says branch=main, and the repository default branch is main. The label is stale, the links are correct, so trust the URLs. The same table also keeps an Appveyor badge and the tree still carries appveyor.yml alongside a GitHub Actions workflow, which means continuous integration spans two systems rather than having fully moved to one.

## Reading the demo directory as the real documentation

The README points at the demo directory in the source package for more usage examples, and that directory is the most efficient way to learn the API. It holds batch_processing.py, benchmark.py, cwt_analysis.py, dwt2_dwtn_image.py, dwt_signal_decomposition.py, dwt_swt_show_coeffs.py, fswavedecn.py, fswavedecn_mondrian.py, image_blender.py, mra2d.py, mra_vs_swt.py, plot_demo_signals.py, plot_wavelets.py, plot_wavelets_pyqtgraph.py, swt2.py, swt_variance.py, waveinfo.py, wp_2d.py, wp_nd.py, wp_scalogram.py and wp_visualize_coeffs_distribution.py.

The filenames encode the distinctions the feature list compresses into one line each. mra_vs_swt.py is a comparison between two transform families rather than a demonstration of one. fswavedecn_mondrian.py names a boundary handling mode, which tells you boundary behavior is treated as a first-class decision. wp_scalogram.py and wp_visualize_coeffs_distribution.py treat wavelet packet output as something with a distribution worth plotting, not just a decomposition to consume.

The most telling entry is _dwt_decompose.c. A C example sitting inside a Python demo folder indicates the C interface is a supported surface rather than an accident of the build, and it is a reminder that the fast path in this library may not be the Python one.

## Version cadence and the license statement worth reading twice

Releases arrive roughly annually: v1.8.0 on 2024-12-04, v1.9.0 on 2025-08-04 and v1.10.0 on 2026-09-07. The project metadata on main already reads version = "1.11.0.dev0", so the default branch is carrying the next minor release while the most recent published version is 1.10.0. When you pin, pin the release you tested rather than the development version on main.

The licensing statement is where the README and the metadata do not agree on their face. The README says PyWavelets is free Open Source software released under the MIT license. The project metadata declares license = "MIT and BSD-3-Clause" and lists license-files as LICENSE together with a glob for licenses_bundled. The tree contains that licenses_bundled directory.

Both statements can hold at once, because a library that bundles third-party code often carries terms inherited from that code. The actionable reading is that if you redistribute PyWavelets inside a larger product, do not treat the single MIT sentence as covering everything shipped in the wheel, and read the licenses in that bundled directory first. You will not find a conflict here so much as an invitation to check.

Two smaller signals are worth carrying into a citation. The README directs security reports to a Tidelift address rather than to a private advisory channel, and notes that development has been supported in part by Tidelift since 2019. For reproducibility, the README points at a Journal of Open Source Software article with DOI 10.21105/joss.01237 and a Zenodo concept DOI of 10.5281/zenodo.1407171, where DOIs for past versions can be resolved. If your results need to be checkable in five years, use the Zenodo record rather than the tag name.

## Conclusion

PyWavelets is worth understanding as a compiled numerical extension rather than a pure Python package, because that single fact explains most of what the README describes. It needs a C compiler and a recent Cython to build, it offers both single and double precision and both real and complex arithmetic rather than a single default path, and it publishes prebuilt wheels for Intel Linux, Windows and macOS so most people never see that machinery. It also has a long lineage that the project is upfront about, starting from a 2006 thesis on classifying medical signals and moving to a new repository in 2013 without becoming a fork. Two details deserve a second look before you pin anything. The README states a single MIT license while the project metadata declares MIT and BSD-3-Clause alongside a licenses_bundled directory, so read that directory if you redistribute. And the README describes Python >=3.12 and NumPy >=2.0.0,<3 with no older path, so check your interpreter before upgrading anything. The demo directory is the fastest way to learn the API, and its paired files make the tradeoffs between transform families concrete without reading the docs.

## FAQ

### How do I install PyWavelets?

Run `pip install PyWavelets`, which gives you a precompiled wheel on Intel Linux, Windows and macOS. Conda users can use `conda install -c conda-forge pywavelets`. Building from source requires a working C compiler and a recent Cython, and you run `pip install .` from the directory containing pyproject.toml. Linux distribution packages exist but the README warns they tend to be moderately out of date.

### What is the difference between CWT and DWT?

The DWT is the discrete wavelet transform, available here in forward and inverse form in one, two and n dimensions, with multilevel variants. The CWT is the continuous wavelet transform, offered in one dimension, and it scales a wavelet across position and scale rather than decimating the signal into a fixed set of coefficients. Because PyWavelets offers both, choosing between them is a choice about what your signal's structure looks like rather than a limitation of the library.

### What is a wavelet used for?

A wavelet is a basis function localized in both time and frequency, which is the difference from a Fourier basis that is localized only in frequency. That time localization lets a transform say when a feature occurred rather than only which frequencies are present. PyWavelets applies this through its discrete, multilevel, stationary, packet and continuous transforms, and the demo directory includes scripts for signal decomposition, image decomposition, wavelet packet scalograms and 2D approximation.

### Are wavelets still used?

Yes. PyWavelets is marked as a production stable library, supports Python 3.12 through 3.15, and shipped v1.10.0 in September 2026 after releases in 2025 and 2024. It remains the standard Python implementation for wavelet work, keeps compatibility with the Matlab Wavelet Toolbox, ships a curated set of over 100 built-in filters, and its repository records active development rather than maintenance mode.

## Sources

- [License: MIT](https://github.com/PyWavelets/pywt/blob/main/LICENSE)
- [Project website](http://pywavelets.readthedocs.org)
- [PyWavelets/pywt on GitHub](https://github.com/PyWavelets/pywt)
- [README](https://github.com/PyWavelets/pywt/blob/main/README.md)
- [Releases](https://github.com/PyWavelets/pywt/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pywavelets-pywt
