I have a data.frame of b/w raster image data that I'm using as a background/base layer. It has three columns: x, y, z. Where x and y are the respective coordinates and z is a continuous value defining a 512 x 512 image. I set this background fill to a black-white gradient and plot using geom_raster()
in ggplot2
and then save the image to a PDF file.
### MWE of base layer
# original 512x512 data is read in from a file in matrix format, so here's a mocked up example of same:
h = matrix(data = rep(c(1:512), 512), byrow = T, nrow = 512, ncol = 512)
# convert to data.frame with all the rows of z-data in first column
h = data.frame(z = as.vector(t(h)))
# create equally spaced 512x512 x and y pixel coordinate vectors
x = c(-255:256)
y = c(-255:256)
# add x and y coordinate vectors to the data.frame
h$x = rep(t(x), 512)
h$y = rep(t(-y), each=512)
# plot the data
ggplot() +
coord_fixed() +
geom_raster(data=h, aes(x,y,fill=z)) +
scale_fill_gradient(low="black", high="white", na.value="transparent")
# save to png
ggsave("testbaseplot.png", dpi=300)
This gives the desired result in the saved file.
Next, on top of that base layer I plot one or more additional layers. These layers also have x, y, and r. Where r is either a continuous or discrete value depending on the region. For example, a layer defining region borders would label the discrete regions, whereas a layer defining topology in the region would define the topology.
Ideally, I'd like to use geom_raster()
twice, once for each layer (base, overlay) and use a different aes(fill=)
on each layer, with a different scale_fill_*()
for each layer as well. However, attempting this results in errors:
# MWE of mock overlay = 4 square labeled regions
# create z-data for some example shapes
r = data.frame(r = as.vector(c(rep(rep(c('a','b'),each=100),100),
rep(rep(c('c','d'),each=100),100))))
# create x and y coordinates
r$x = rep(c(-99:100),200)
r$y = rep(c(-99:100),each=200)
# plot base layer and 1 overlay layer, both as geom_raster
ggplot() +
coord_fixed() +
geom_raster(data=h, aes(x,y,fill=z)) +
scale_fill_gradient(low="black", high="white", na.value="transparent") +
geom_raster(data=r, aes(x,y,fill=r)) +
scale_fill_manual(values=c("red","white","blue","yellow"))
Error Message:
Scale for 'fill' is already present. Adding another scale for 'fill', which will replace the existing scale. Error: Continuous value supplied to discrete scale
I thought maybe I could do one geom_raster()
with aes(fill=z)
and one with the aes(colour=r)
and scale_colour_manual
but geom_raster()
does not recognize the aes(colour=)
option, so I used geom_tile(aes(colour=r))
instead:
# plot looks fine
ggplot() +
coord_fixed() +
geom_raster(data=h, aes(x,y,fill=z)) +
scale_fill_gradient(low="black", high="white", na.value="transparent") +
geom_tile(data=r, aes(x,y,colour=r), fill="transparent") +
scale_colour_manual(values=c("red","white","blue","yellow"))
# saved file does not
ggsave("testlayerplot.png", dpi=300)
The plot looks fine in RStudio's previewer window, but when saved as a file (pdf, png, etc.), the tile layer has a grid of unwanted lines on it.
I believe these lines are showing up because the geom_tile
default fill is grey. Is this due to the file format? Due to the default grey fill of geom_tile
ignoring the fill="transparent"
option? Some other reason?
I feel like I am approaching this wrong. I am probably converting the original raster data in matrix format into x,y,z data.frame
format unnecessarily... and because I understand data.frame
format better.
First part: Can I use ggplot
to plot one raster over another without getting the unwanted lines? If so, how? Can I also add an alpha=.5
transparency to the overlay layer?
Second part: Is there a way that I can plot the original raster matrix format without converting to x,y,z data.frame
format first? If so, how? Can I set transparency on the overlay layer?
With a little work, you can use annotate
to create the background without mapping, so the fill scales remains available for the center:
h$z <- (h$z - min(h$z)) / diff(range(h$z))
ggplot() +
coord_fixed() +
annotate(
geom = 'raster',
x = h$x,
y = h$y,
fill = scales::colour_ramp(c("black", "white"))(h$z)
) +
geom_raster(aes(x, y, fill = r), data = r) +
scale_fill_manual(values=c("red", "white", "blue", "yellow"))