>>> from __future__ import print_function
Wavelet Packets¶
Import pywt¶
>>> import pywt
>>> def format_array(a):
... """Consistent array representation across different systems"""
... import numpy
... a = numpy.where(numpy.abs(a) < 1e-5, 0, a)
... return numpy.array2string(a, precision=5, separator=' ', suppress_small=True)
Create Wavelet Packet structure¶
Ok, let’s create a sample WaveletPacket
:
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
The input data
and decomposition coefficients are stored in the
WaveletPacket.data
attribute:
>>> print(wp.data)
[1, 2, 3, 4, 5, 6, 7, 8]
Nodes
are identified by paths
. For the root
node the path is ''
and the decomposition level is 0
.
>>> print(repr(wp.path))
''
>>> print(wp.level)
0
The maxlevel
, if not given as param in the constructor, is automatically
computed:
>>> print(wp['ad'].maxlevel)
3
Traversing WP tree:¶
Accessing subnodes:¶
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
First check what is the maximum level of decomposition:
>>> print(wp.maxlevel)
3
and try accessing subnodes of the WP tree:
1st level:
>>> print(wp['a'].data) [ 2.12132034 4.94974747 7.77817459 10.60660172] >>> print(wp['a'].path) a2nd level:
>>> print(wp['aa'].data) [ 5. 13.] >>> print(wp['aa'].path) aa3rd level:
>>> print(wp['aaa'].data) [ 12.72792206] >>> print(wp['aaa'].path) aaaUps, we have reached the maximum level of decomposition and got an
IndexError
:>>> print(wp['aaaa'].data) Traceback (most recent call last): ... IndexError: Path length is out of range.
Now try some invalid path:
>>> print(wp['ac'])
Traceback (most recent call last):
...
ValueError: Subnode name must be in ['a', 'd'], not 'c'.
which just yielded a ValueError
.
Accessing Node’s attributes:¶
WaveletPacket
object is a tree data structure, which evaluates to a set
of Node
objects. WaveletPacket
is just a special subclass
of the Node
class (which in turn inherits from the BaseNode
).
Tree nodes can be accessed using the obj[x]
(Node.__getitem__()
)
operator.
Each tree node has a set of attributes: data
, path
,
node_name
, parent
, level
,
maxlevel
and mode
.
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
>>> print(wp['ad'].data)
[-2. -2.]
>>> print(wp['ad'].path)
ad
>>> print(wp['ad'].node_name)
d
>>> print(wp['ad'].parent.path)
a
>>> print(wp['ad'].level)
2
>>> print(wp['ad'].maxlevel)
3
>>> print(wp['ad'].mode)
symmetric
Collecting nodes¶
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
We can get all nodes on the particular level either in natural
order:
>>> print([node.path for node in wp.get_level(3, 'natural')])
['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd']
or sorted based on the band frequency (freq
):
>>> print([node.path for node in wp.get_level(3, 'freq')])
['aaa', 'aad', 'add', 'ada', 'dda', 'ddd', 'dad', 'daa']
Note that WaveletPacket.get_level()
also performs automatic decomposition
until it reaches the specified level
.
Reconstructing data from Wavelet Packets:¶
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
Now create a new Wavelet Packet
and set its nodes with
some data.
>>> new_wp = pywt.WaveletPacket(data=None, wavelet='db1', mode='symmetric')
>>> new_wp['aa'] = wp['aa'].data
>>> new_wp['ad'] = [-2., -2.]
For convenience, Node.data
gets automatically extracted from the
Node
object:
>>> new_wp['d'] = wp['d']
And reconstruct the data from the aa
, ad
and d
packets.
>>> print(new_wp.reconstruct(update=False))
[ 1. 2. 3. 4. 5. 6. 7. 8.]
If the update
param in the reconstruct method is set to False
, the
node’s data
will not be updated.
>>> print(new_wp.data)
None
Otherwise, the data
attribute will be set to the reconstructed
value.
>>> print(new_wp.reconstruct(update=True))
[ 1. 2. 3. 4. 5. 6. 7. 8.]
>>> print(new_wp.data)
[ 1. 2. 3. 4. 5. 6. 7. 8.]
>>> print([n.path for n in new_wp.get_leaf_nodes(False)])
['aa', 'ad', 'd']
>>> print([n.path for n in new_wp.get_leaf_nodes(True)])
['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd']
Removing nodes from Wavelet Packet tree:¶
Let’s create a sample data:
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
First, start with a tree decomposition at level 2. Leaf nodes in the tree are:
>>> dummy = wp.get_level(2)
>>> for n in wp.get_leaf_nodes(False):
... print(n.path, format_array(n.data))
aa [ 5. 13.]
ad [-2. -2.]
da [-1. -1.]
dd [ 0. 0.]
>>> node = wp['ad']
>>> print(node)
ad: [-2. -2.]
To remove a node from the WP tree, use Python’s del obj[x]
(Node.__delitem__
):
>>> del wp['ad']
The leaf nodes that left in the tree are:
>>> for n in wp.get_leaf_nodes():
... print(n.path, format_array(n.data))
aa [ 5. 13.]
da [-1. -1.]
dd [ 0. 0.]
And the reconstruction is:
>>> print(wp.reconstruct())
[ 2. 3. 2. 3. 6. 7. 6. 7.]
Now restore the deleted node value.
>>> wp['ad'].data = node.data
Printing leaf nodes and tree reconstruction confirms the original state of the tree:
>>> for n in wp.get_leaf_nodes(False):
... print(n.path, format_array(n.data))
aa [ 5. 13.]
ad [-2. -2.]
da [-1. -1.]
dd [ 0. 0.]
>>> print(wp.reconstruct())
[ 1. 2. 3. 4. 5. 6. 7. 8.]
Lazy evaluation:¶
Note
This section is for demonstration of pywt internals purposes only. Do not rely on the attribute access to nodes as presented in this example.
>>> x = [1, 2, 3, 4, 5, 6, 7, 8]
>>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='symmetric')
At first the wp’s attribute
a
is None>>> print(wp.a) None
Remember that you should not rely on the attribute access.
At first attempt to access the node it is computed via decomposition of its parent node (the wp object itself).
>>> print(wp['a']) a: [ 2.12132034 4.94974747 7.77817459 10.60660172]
Now the
wp.a
is set to the newly created node:>>> print(wp.a) a: [ 2.12132034 4.94974747 7.77817459 10.60660172]
And so is
wp.d
:>>> print(wp.d) d: [-0.70710678 -0.70710678 -0.70710678 -0.70710678]