Matrix to image with exactly 1 pixel for each element
I am interested in converting a matrix to an image (element value = pixel intensity), a bit like:开发者_如何学Go R - image of a pixel matrix?
However I need the size of the image to be exactly (in pixels) the size of the matrix. So if the matrix is 234x14 so should be the generated image.
Preference for a solution using no additional R package (like in answer to question lined above), but everything would be fine as well.
One way is to avoid the R devices completely, and rely on the GDAL drivers in rgdal
.
m <- matrix(rep(1:234, each = 14), ncol = 14, byrow = TRUE)
l <- list(x = 1:nrow(m), y = 1:ncol(m), z = m)
library(rgdal)
x <- image2Grid(l)
writeGDAL(x, "out.tif")
There are other drivers in GDAL, but "GeoTIFF" is the default, and the defaults will preserve the values accurately (within the numeric limits of R and GDAL). This is just a single band raster, but it will work the same for multiple attributes.
The real limit here is the target you have for the file, and whether it can read the resulting image in the way that you want. GDAL has all the options you would need, but whether the defaults are right and what you really need depends on details.
y <- readGDAL("out.tif")
all.equal(as.image.SpatialGridDataFrame(y)$z, m)
[1] TRUE
Here is a floating point example that shows the numeric limits more realistically:
set.seed(1)
m <- matrix(runif(234 * 14), ncol = 14)
l <- list(x = 1:nrow(m), y = 1:ncol(m), z = m)
library(rgdal)
x <- image2Grid(l)
writeGDAL(x, "out.tif")
y <- readGDAL("out.tif")
all.equal(as.image.SpatialGridDataFrame(y)$z, m)
[1] "Mean relative difference: 1.984398e-08"
Another way is the pnm format that is used by pixmap
. See
library(pixmap)
?write.pnm
It is an extra package, but you could try pixmap: http://cran.r-project.org/web/packages/pixmap/index.html
If you want animated images, you can write animated gifs from matrices using caTools
.
Here is an alternative way to solve the problem. Included in the example are ways to add margins with axes information, how to normalize and floor the data to be plotted + use a colour (blue) for a specific level (zero). Substitute and with the specific data you want to use and change {lm, bm, tm, rm} to different values to resize the four margins (all measures in pixels):
maxv <- 500
v <- t(<matrix>)
d <- <vector>
di <- <vector>
dm <- <vector>
nr <- nrow(v)
nc <- ncol(v)
library(grid)
vnorm <- v
for (r in 1:nr) {
for (c in 1:nc) {
vnorm[r,c] <- min(1, v[r, nc-c+1]/500)
if (vnorm[r,c] == 0) {vnorm[r,c] <- "blue"}
else {vnorm[r,c] <- grey(vnorm[r,c])}
}
}
vnorm <- t(vnorm)
x <- seq(1, nr)
y <- rep(1, nr)
xrange <- range(d)
yrange <- c(0, 24)
bm <- 90
lm <- 40
tm <- 12
rm <- 12
png(file="graph.png", width=nr+lm+rm, height=nc+tm+bm)
par(mai=c(bm/72, lm/72, tm/72, rm/72))
plot(d, y, ann=FALSE, xlim=xrange, ylim=yrange, axes=FALSE, xaxs="i", yaxs="i")
axis(1, at=dm,labels=dm, col.axis="black", las=2)
axis(2, at=seq(0,24),labels=seq(0,24), col.axis="black", las=2)
rasterImage(vnorm, xrange[1], yrange[1], xrange[2], yrange[2], interpolate=FALSE)
dev.off()
精彩评论