```
>>> 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]