Tutorial: Inverse Matrix Patterns

Our goal in this tutorial is to write a script that will allow us to visualize the relative values of the elements of a matrix. We will need to decide on a colormap, a way of mapping an integer value in the interval [0 Imax) to a color value. Actually, since color is represented with three components representing red, green, and blue, we will need to produce three color values for each numeric value. Furthermore, we will need to transform the input matrix so that its elements (approximately) retain their relative magnitudes but are in the range [0 Imax) . Finally, we will use a Tk canvas widget to draw the matrix. For each element in the matrix, we will create a rectangle in the canvas with the computed background color. The pseudo-code for what we want to do then looks like:

  1. create a colormap
  2. get an input matrix (we will generate a random one)
  3. transform the matrix
  4. decompose the normalized matrix into three matrices corresponding to red, green, and blue components
  5. draw a Tk canvas

1) Create a MathViews Interpreter

First let us create a MathViews interpreter called M. We assume that package Mxt has already been loaded (as described in the installation and configuration instructions), so that command minterp is available.

% minterp create M

2) Create the Colormap

We've already done some of the hard work: We created a MathViews function called clrmap which will create three required colormap vectors. Here it is:

function [ r , g , b ] = clrmap( num_colors ) 
% black-red-yellow-white colormap
third_num_colors = floor( num_colors / 3 );
% create red component vector
r = ones(num_colors,1);
r(1:third_num_colors+1) = [ 0 : 1/(third_num_colors) : 1 ]';
r = round( r * 255 );
% use vector shifting operator to create green and blue 
% component vectors
g = r >> third_num_colors;
b = g >> third_num_colors;

Cut the text for the clrmap function and put it in a file called clrmap.m. Now reset the _MVPATH variable so it contains the directory where clrmap.m lives. This is needed in order make the MathViews interpreter re-examine the contents of the directories listed in the _MVPATH search path:

% M eval { _MVPATH = [ _MVPATH ':/my/dir' ] }

You should now be able to invoke the function as follows:

% M eval { [ R, G, B ] = clrmap( 9 ); }
% M eval { [ R G B ] }
ans =  

0 0 0
85 0 0
170 0 0
255 0 0
255 85 0
255 170 0
255 255 0
255 255 85
255 255 170

What we've just done is create a colormap containing 9 colors spanning black to white, with red and yellow in between. R(i), G(i), and B(i) contain the red, green, and blue components of ith color in the color map. Later, we will use var option to cast the values in R, G, and B into their 16-bit hexadecimal representations, need by Tk to specify color. For example:

% M eval B9 = B(9)
B9 =  

170.0000

% M var B9 -format %x aa

The problem with a colormap of size nine is that it only lets us visually distinguish between nine different values. Let us instead use a colormap of size 128:

% M eval { [ R, G, B ] = clrmap( 128 ); }

Note how we used the semicolon after the MathViews command to suppress output.

3) Generating a Matrix

Let us create a 40×40 random symmetric matrix using MathViews' rand function. rand returns a matrix whose values are drawn from a uniform probability distribution from zero to one.

% set n 40
% M eval "x = rand($n);"
% M eval "x = x' * x;"

4) Transforming the Matrix

Now, let us transform the random matrix x into another matrix y. We need to scale and translate all of x's values so they are in the range [1 128]. Recall that Imax=128 is the value we chose as the size of the colormap. First, let us compute the range of values in x.

% M eval max_x = max(x(:))
max_x =   

16.7125
% M eval min_x = min(x(:)) min_x =
6.1320
% M eval range_x = max_x - min_x range_x =
10.5805

Of course, your particular numbers may vary, since the random matrix you generate is likely to be quite different than the one we are using for this example. Now, let us create a new matrix y which is the result of scaling and translating x:

% M eval {
y = x - min_x;
y = y / range_x;
y = y * ( 128 - 1 );
y = round( y ) + 1;
} 

The elements of y should range between 1 and 128. To confirm this:

% M eval max(y(:))
ans =   

128
% M eval min(y(:)) ans =
1

4) Decomposing Into Colors

From y and our colormap, we will now create three matrices (Ry, Gy, By) which contain the red, green, and blue components of each element of y. For example, suppose that y(3,29)=103. Then, we want Ry(3,29) to equal R(103). Clever use of MathViews' colon (:) operator allows us to do this mapping without needing nested for loops as follows:

% M eval { 
Ry = y;
Gy = y;
By = y;
Ry(:) = R(y(:));
Gy(:) = G(y(:));
By(:) = B(y(:));
}

5) Drawing the Tk Canvas

From now-on, all our code will be in Tcl. First, let us convert Ry, Gy, and Byinto Tcl lists using the var option:

% set ry [ M var Ry -format %0.2x ]
% set gy [ M var Gy -format %0.2x ]
% set by [ M var By -format %0.2x ]

Since Tk represents color in hexadecimal, we used the-format %0.2x option. Each command created a list of sub-lists. Each sub-list corresponds to a matrix column. (We did not show the output of the commands here because they are a few screens long.) Now, let us create the Tk canvas .c. For each element in the matrix, we will create a rectangle in .c with the computed background color. If we make each rectangle a three pixel-wide square, then our canvas to have height and width of 3×40=120 pixels:

% canvas .c -width 120 -height 120
% pack .c

We create the filled rectangles by iterating over the Tcl lists ry, gy, and by. For each element, we compose a color by concatenating the elements extracted from these three lists. We use the variables xp and yp to denote the top-left corner position of each rectangle within the canvas. We also use variables j and i as column and row indices, respectively:

% for { set xp 0; set j 0 } { $j < 40 } { incr xp 3; incr j } {
    set r_col [ lindex $ry $j ]
    set g_col [ lindex $gy $j ]
    set b_col [ lindex $by $j ]
    for { set yp 0; set i 0 } { $i < 40 } { incr yp 3; incr i } {
	set r_color [ lindex $r_col $i ]
	set g_color [ lindex $g_col $i ]
	set b_color [ lindex $b_col $i ]
	set color \#$r_color$g_color$b_color
	.c create rectangle $xp $yp [ expr $xp + 3 ] [ expr $yp + 3 ] \
		-fill $color -outline ""
    }
}

The resulting canvas should something like:


The MathWizards

Last modified: Mon Nov 30 10:43:04 PST 1998