Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining a map and a XY ggplot chart in R

Tags:

r

ggplot2

ggpubr

I need to combine a map, which represents an archaeological site, with an XY ggplot chart of different archaeological objects. The map is in a tiff file and must respect its proportion.

First, this is the map, highlighting the reference scales in red (in X axis, from -6000 to -4000 there are 20 meters of distance, for instance; in Y axis, from 900 to 2100 there are 12 meters). enter image description here

My ggplot chart is obtained by running this code:

archaeo <- ggplot() + 
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2+250, b = Diameter_N.S/2+250, angle = 0), 
        lwd=0, col="darkgray", fill="gray", alpha=0.15) +     
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2+120, b = Diameter_N.S/2+120, angle = 0), 
        lwd=0, col="darkgray", fill="gray", alpha=0.25) + 
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2, b = Diameter_N.S/2, angle = 0), 
        lwd=0.5, col="darkgray", fill="gray", alpha=0.75) + 
    geom_point(data=Unit_H, aes(X, Y), size = 0.5) + 
    geom_point(data=Refits_H_trans, aes(x,y,group=sample, colour=factor(sample))) + 
    geom_line(data=Refits_H_trans, lwd=0.2, lty=1, aes(x,y, group=sample, colour=factor(sample))) + 
    coord_fixed() + 
    theme_bw() + 
    theme(legend.position="none") + 
    ggtitle("Unit H") + 
    xlim(-6600,-3800) + 
    ylim(400,2400)

The resulting chart is:

enter image description here

Now, my problem, which deals with the inclusion of the map as background of the ggplot. I used background_image() from ggpubr, with this result:

map_levelH <- readPNG("Planta H-I.png")

Map.archaeo <- ggplot() + 
    background_image(map_levelH) + 
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2+250, b = Diameter_N.S/2+250, angle = 0), 
        lwd=0, col="darkgray", fill="gray", alpha=0.15) +     
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2+120, b = Diameter_N.S/2+120, angle = 0), 
        lwd=0, col="darkgray", fill="gray", alpha=0.25) + 
    geom_ellipsis(data=Unit_H, 
        aes(x0 = X, y0 = Y, a = Diameter_E.W/2, b = Diameter_N.S/2, angle = 0), 
        lwd=0.5, col="darkgray", fill="gray", alpha=0.75) + 
    geom_point(data=Unit_H, aes(X, Y), size = 0.5) + 
    geom_point(data=Refits_H_trans, aes(x,y,group=sample, colour=factor(sample))) + 
    geom_line(data=Refits_H_trans, lwd=0.2, lty=1, aes(x,y, group=sample, colour=factor(sample))) + 
    coord_fixed() + 
    theme_bw() + 
    theme(legend.position="none") + 
    ggtitle("Unit H") + 
    xlim(-6600,-3800) + 
    ylim(400,2400)

enter image description here

As you can see, scales of the ggplot and the map don't match. So, my questions are:

  • How can I georeference the map with the values of the ggplot X and Y axes?
  • I need to keep the proportion of the image, in order not to distort it. How can I do it? I am asking this because if I change the xlim values, the image also change and its proportion changes.
like image 886
antecessor Avatar asked Apr 11 '18 14:04

antecessor


Video Answer


1 Answers

I've recreated a simple example where this problem exists:

library(tidyverse)

# create the background
bck_square <- data.frame(x=c(1,1,0,0),y=c(0,1,1,0))
p <- ggplot(bck_square, aes(x=x, y=y)) +
  geom_point(size=10, color="red") + 
  theme(panel.border=element_blank(), 
        panel.grid.major=element_blank(),
        panel.grid.minor=element_blank(),
        #panel.background=element_blank(), keep the background to see where image ends
        axis.text=element_blank(),
        axis.ticks=element_blank(),
        axis.title=element_blank())
p

enter image description here

I will save the image to be used as a background for my figures:

ggsave("temp.png",p)
img <- readPNG("temp.png")

Setting the background using background_image from the ggpubr package, the old square does not line up with the new square, even though the data is the same. This is expected, as ggsave adds a thin border around the image

library(ggpubr)
ggplot(bck_square, aes(x, y)) +
  background_image(img) +
  geom_point()

enter image description here

However, by using annotation_custom instead (see this guide), you can adjust where the minimum and maximum for the image should be. Playing around with the border parameters I was able to get the image background and figure to line up.

library(png)
library(grid)
min_border <- .064
max_border <- .061
ggplot(bck_square, aes(x, y)) +
  annotation_custom(g,xmin=-min_border, xmax=1+max_border, ymin=-min_border, ymax=1+max_border) +
  geom_point()

enter image description here

This method should work with a tiff file. Another potential solution could be spatial data transformations using rspatial (see the documentation here) but this may over-complicate the issue.

like image 122
cacti5 Avatar answered Oct 28 '22 19:10

cacti5