简体   繁体   中英

R ggplot: geom_tile lines in pdf output

I'm constructing a plot that uses geom_tile and then outputting it to .pdf (using pdf("filename",...)). However, when I do, the .pdf result has tiny lines (striations, as one person put it) running through it. I've attached an image showing the problem. 最小的例子

Googling let to this thread , but the only real advice in there was to try passing size=0 to geom_tile, which I did with no effect. Any suggestions on how I can fix these? I'd like to use this as a figure in a paper, but it's not going to work like this.

Minimal code:

require(ggplot2)
require(scales)
require(reshape)

volcano3d <- melt(volcano) 
names(volcano3d) <- c("x", "y", "z") 
 v <- ggplot(volcano3d, aes(x, y, z = z)) 

pdf("mew.pdf")
print(v + geom_tile(aes(fill=z)) + stat_contour(size=2) + scale_fill_gradient("z"))

This happens because the default colour of the tiles in geom_tile seems to be white.

To fix this, you need to map the colour to z in the same way as fill .

print(v + 
  geom_tile(aes(fill=z, colour=z), size=1) + 
  stat_contour(size=2) + 
  scale_fill_gradient("z")
)

在此处输入图片说明

Try to use geom_raster :

pdf("mew.pdf")
print(v + geom_raster(aes(fill=z)) + stat_contour(size=2) + scale_fill_gradient("z"))
dev.off()

good quality in my environment.

在此处输入图片说明

I cannot reproduce the problem on my computer (Windows 7), but I remember it was a problem discussed on the list for certain configurations. Brian Ripley (if I remember) recommended

CairoPDF("mew.pdf") # Package Cairo

to get around this

In the interests of skinning this cat, and going into waaay too much detail, this code decomposes the R image into a mesh of quads (as used by rgl ), and then shows the difference between a raster plot and a "tile" or "rect" plot.

library(raster)
im <- raster::raster(volcano)
## this is the image in rgl corner-vertex form
msh <- quadmesh::quadmesh(im)

## manual labour for colour scaling
dif <- diff(range(values(im)))
mn <- min(values(im))
scl <- function(x) (x - mn)/dif

This the the traditional R 'image', which draws a little tile or 'rect()' for every pixel.

list_image <- list(x = xFromCol(im), y = rev(yFromRow(im)), z = t(as.matrix(im)[nrow(im):1, ]))
image(list_image)

It's slow, and though it calls the source of 'rect()' under the hood, we can't also set the border colour. Use 'useRaster = TRUE' to use 'rasterImage' for more efficient drawing time, control over interpolation, and ultimately - file size.

Now let's plot the image again, but by explicitly calling rect for every pixel. ('quadmesh' probably not the easiest way to demonstrate, it's just fresh in my mind).

## worker function to plot rect from vertex index
rectfun <- function(x, vb, ...) rect(vb[1, x[1]], vb[2,x[1]], vb[1,x[3]], vb[2,x[3]], ...)

## draw just the borders on the original, traditional image
apply(msh$ib, 2, rectfun, msh$vb, border = "white")

Now try again with 'rect'.

## redraw the entire image, with rect calls 
##(not efficient, but essentially the same as what image does with useRaster = FALSE)
cols <- heat.colors(12)
## just to clear the plot, and maintain the plot space
image(im, col = "black")  
for (i in seq(ncol(msh$ib))) {
  rectfun(msh$ib[,i], msh$vb, col = cols[scl(im[i]) * (length(cols)-1) + 1], border = "dodgerblue")
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM