Search code examples
rimageggplot2geo

How do I save a tiff background image in R with exactly the same dimensions as my input tiff


I am adding a background image in R using ggplot. I am doing this in an iterative process, building up multiple slides with the same background.

I have an input worldmap in tiff format, I read it into a ggmap process and then write it out as a tiff file.

world map with urban areas highlighted

I have two problems which I would like some help with: 1. The saved world map picture is written slightly down and to the right in comparison to the input file. Look closely to see this. 2. The saved file loses resolution.

world_background <-tiff::readTIFF("world_background_in.tiff", native = TRUE)
myplt <- ggplot() +
    theme_void() + theme(legend.position="none") +
    annotation_custom(rasterGrob(world_background, 
                                 width = unit(1,"npc"), 
                                 height = unit(1,"npc")), 
                      -Inf, Inf, -Inf, Inf) +
    scale_x_continuous(limits = c(-180, 180)) +
    scale_y_continuous(limits = c(-79.99688, 79.99825))
tiff("world_packground_out.tiff", width=1024, height=580, res=300, compression = "lzw")
print(myplt)
dev.off()

If you run this on an iterative basis, using the saved file as input for the next iteration, you will see that the world pic slides down and right for each output you produce, and the resolution becomes increasingly grainy.

Any suggestion on to keep the image in exactly the same location? And how do I maintain my resolution?

Note: The uploaded image is saved in png format (I think!). If you run my code with png input, the problem is the same


Solution

  • Not sure what is the issue you're facing, response was too long to post in a comment, hence an answer.

    I'm using magick::image_read() to read the background image. Since I don't know what you're trying to plot, I'm using mtcars as a sample dataset to check if it works in a loop - both the variable to be plotted and scale_y_continuous are dependant on the column being plotted which might be similar to your use case.

    lapply(c('data.table', 'ggplot2', 'grid', 'png', 'magick'), 
           library, character.only = T)
    
    img <- image_read('https://i.sstatic.net/IwjyT.png')
    dat <- as.data.table(mtcars)
    plot_list <- lapply(colnames(dat)[1:5], function(z){
      plt <- ggplot(dat, aes_string(x = 'wt', y = z)) + 
        theme(legend.position = 'none') + 
        annotation_custom(grob = rasterGrob(image = img, 
                                            width = unit(1, 'npc'), 
                                            height = unit(1, 'npc')), 
                          xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf) + 
        geom_point() + geom_line() + 
        scale_x_continuous(limits = dat[, range(wt)]) + 
        scale_y_continuous(limits = dat[, range(get(z))])
    
      ggsave(filename = sprintf('%s vs Wt.png', z), plot = plt, device = 'png')
    
      return(plt)
    
    })
    

    I found no issues with the plots - confirmed by saving the plot locally. The only time there was a difference in the image size was when the y-axis had more digits for the tick marks (e.g. when plotting cyl vs when plotting hp).

    I tested this with theme_void as well - it only removed the x, y axes and made no difference to the plot itself.