Other Visualizations

xyzpy has two functions for visualizing arrays that are focused on quickly getting an overview of the values, and unlike plots don’t require or assume any particular relationship between the dimensions. Think of these as visual pretty print functions. They are:

%config InlineBackend.figure_formats = ['svg']
import numpy as np

import xyzpy as xyz

rng = np.random.default_rng(42)

Visualizing matrices

visualize_matrix is for 2D or 1D arrays or sequences of arrays. It is a wrapper around matplotlib.pyplot.imshow that adds some convenient and consistent defaults and a few extra features.

For real arrays it shows positive numbers as blue and negative numbers as orange, the maximum magnitude is displayed below the legend (colorbar). By default the alpha channel is also mapped to magnitude, so that the more transparent a pixel is, the closer to zero the value is. This can be disabled with the alpha_map argument.

x = rng.normal(size=(50, 100))
xyz.visualize_matrix(x);
_images/ea011c5886a91d9c29488e94be49b177d99ce7d0a058a2c655ef55ffa3093af8.svg

For complex matrices a color wheel is used, with positive imaginary values shown as green and negative imaginary values shown as pink. The magnitude is still shown below the legend, and the alpha channel is mapped to magnitude as with real matrices.

x = rng.normal(size=(50, 30)) + 1j * rng.normal(size=(50, 30))
xyz.visualize_matrix(x);
_images/b02c451fce86a9d1c0cf71fb706190ac76f8ee5ec905dc5420ec681683d1bb7c.svg

If you supply a sequence of arrays, they will shown as a row of images, sharing the same magnitude scale and legend (colorbar). 1D arrays shown as diagonal matrices.

fig, axs = xyz.visualize_matrix(
    [
        rng.normal(size=(10, 7)),
        rng.normal(size=(7)),
        rng.normal(size=(7, 11)),
    ]
)
_images/ce36991c2ef7ae54d04ccf148ea6590567e8848234affea44261f4acafca69f8.svg

More examples can be found here: Visualizing Linear Algebra Decompositions.

Visualizing tensors

visualize_tensor is for ND arrays or sequences of arrays. It works by assigning an angle and associated unit vector to each dimension. The values are then drawn as circles on a grid which connects all neighboring points. The color of each circle, as with visualize_matrix, is mapped to the magnitude and sign or phase of the number.

x = rng.normal(size=(20, 40, 3)) + 1j * rng.normal(size=(20, 40, 3))

# the compass kwarg shows which angles correspond to which dimensions
xyz.visualize_tensor(x, compass=True);
_images/f7e334e154071a6d4f04c9e039823c5929e99025c6a5e42fe25b8e63324d2f1f.svg
import matplotlib.pyplot as plt

fig, axs = plt.subplots(1, 4, figsize=(10, 2.5))
fig.patch.set_alpha(0)

for i, ax in enumerate(axs, 1):
    x = rng.uniform(size=[3] * i)
    xyz.visualize_tensor(x, ax=ax, legend=False, compass=True)
_images/a644dc8e3da35f8b2b2831ad5f19ed5acdd959cb05864bf52e26640166b39539.svg

While the plots can get very busy for higher dimensions, they can still be useful for getting a quick overview of the values in a tensor:

shape = (2,) * 8

x = np.ones(shape)
x *= np.indices(shape).sum(0)
x[(np.indices(shape).sum(0) % 2) == 1] *= -1

xyz.visualize_tensor(x, compass=True);
_images/6a85606d2fc63ba7816cc4baeca65aeb73d356912333da9861c1b2faca4f8cc9.svg

To avoid aliasing / overlapping points, a slight skew is applied to the angles and scales mapped to each dimension, these can be controlled with the skew_angle_factor and skew_scale_factor arguments, for example turning the effect off:

xyz.visualize_tensor(x, skew_angle_factor=0, skew_scale_factor=0);
_images/59f09d96a11a1054cfbda655f9a09a76a30e647d7c1f56c570bf6a54e0e182bc.svg

As an alternative to assigning a seperate angle to each dimension, you can also specify a maximum number of angles, or ‘projections’, and then multiple dimensions will be assigned to the same angle but with different scales (like fusing those axes).

# max_projections=2 results in a matrix like visualization
xyz.visualize_tensor(x, compass=True, max_projections=2);
_images/dda7a72045f102b38ecf24d692702ef50b0dd45d63f5d06047d827744a9fa2a1.svg

This matches up with the data layout if the axes were actually fused (reshaped):

xyz.visualize_tensor(x.reshape(16, 16), compass=True);
_images/67ec2f2e6d9453e46880046fac17d93719c6ce8f4fdb3a18c7c77376a5e659cc.svg