Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

R image() plots matrix rotated?

Tags:

r

image

I've been reading the docs for R image() but I don't get it. Why does this matrix:

> mat1
     [,1] [,2] [,3]
[1,]    1    0    1
[2,]    0    1    0
[3,]    0    0    0

Plotted like this:

> image(c(1:3), c(1:3), mat1)

yield this:

enter image description here

And how can I make the layout the same as the printed matrix? It's not a matter of just taking the transpose to flip x and y, as that ends up with an 'upside down' image.

like image 717
helloB Avatar asked Aug 07 '15 16:08

helloB


3 Answers

You could reverse the matrix, then transpose.

mat1 <- apply(mat1, 2, rev)
image(1:3, 1:3, t(mat1))

It's confusing because it draws by row from bottom up, but R indexes matrices by column, top down. So, the pixels in the first row, from left to right, correspond to the first column in the matrix, top down.

like image 90
Rorschach Avatar answered Nov 16 '22 08:11

Rorschach


when viewing a matrix as image using something like this:

m <- some matrix

image(m) R turns it upside down. After some small headaches, I found this quick fix.

image(m[,nrow(m):1])

nrow(m) gives the number of rows of your matrix

nrow(m):1 makes a sequence backwards

like image 6
Andy Haas Avatar answered Nov 16 '22 09:11

Andy Haas


This seems to be a very common issue for people working with image().

The reason why matrices are plotted 'upside down' is because the image space is defined in Normalized Device Coordinates, aka NDC space. This is a screen-independent coordinate reference system (crs) where the bottom left corner is cell (1,1), and the column numbers proceed from left to right while row numbers increase from the bottom to the top of the matrix,i.e X={0:1}, Y={0:1}

From the docs:

Notice that image interprets the z matrix as a table of f(x[i], y[j]) values, so that the x axis corresponds to row number and the y axis to column number, with column 1 at the bottom, i.e.a 90 degree counter-clock-wise rotation of the conventional printed layout of a matrix.

The point that the rotation is counter-clock-wise should not be overlooked as it affects the order of operations we need to get a plot that looks the way we expect it to.

The top-voted answer is correct in theory:

You could reverse the matrix, then transpose.

However, the simplest way to do this doesn't require any looping and/or apply()

A standard matrix in R prints top to bottom, whereas conventionally we expect to see a row-wise projection of data for display purposes.

> m <- matrix(c(1:9),ncol=3)
> m
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9
> image(m)

The image function in NDC space requires cell (1,1) to be in the lower left corner and outputs the result accordingly. Thus we see the lowest shaded value in the bottom left cell and the highest shaded value in the top right cell.

enter image description here

But notice also that the output from image()is not simply a row-reversal of the standard matrix, but a counter-clock-wise rotation, so that the first column of m becomes the last row of image(m).

So we can take the automatic transpose, but we need to do the reversal properly first, which means we have to sort m by selecting columns. Typically sorting/ordering is done row-wise, but the NDC space inverts everything.

How to reverse rows in matrix?

To reverse the rows of a standard matrix as per above, we would call:

m[nrow(m):1, ]

Instead, here we have to invert the query logic in anticipation of the rotation applied by image(). Thus we get the solution from the previous answer:

> m <- m[,nrow(m):1]
> m
     [,1] [,2] [,3]
[1,]    7    4    1
[2,]    8    5    2
[3,]    9    6    3
> image(m)

enter image description here

Contrast the preceding with a general approach to transforming a standard matrix to NDC space as follows:

m <- t(matrix(c(1:9),ncol=3))
m <- m[nrow(m):1,]

Notice how the transpose is executed first and is assumed to rotate the data clock-wise; and the subset/sort is row-wise. This is a mirror image of our corrective process from before, where we first sort column-wise, then transpose counter-clock-wise with image().

P.S. I strongly advocate exploring graphical parameters and everything associated with par(), either before or in tandem with studying ggplot2 or any of the other graphics packages.

https://www.rdocumentation.org/packages/graphics/versions/3.6.2/topics/par

In many cases, base R functions are quite robust and offer solutions that can liberate the user while expanding our knowledge of the language and increasing our dexterity with the data. Personally, I got hooked on open-source because I felt that every software rig I used was limiting my expressivity in the process of simplification to higher level functions.

Beware any function that produces output which you don't fully understand and can't reproduce manually if necessary. Image() is critical to know because important higher level tools like raster are adapted from it.

like image 1
childerino Avatar answered Nov 16 '22 09:11

childerino