Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ggplot adding image on top-right in two plots with different scales

Tags:

r

ggplot2

I would like to add an image to two ggplots on the top-right. My problem is that the scales are different which is why I have to specify xmin, xmax... for each plot, seperately:

library(ggplot2)
library(png)
library(grid)

# subsetting
am0 <- subset(mtcars, am == 0)
am1 <- subset(mtcars, am == 1)

# ggplot
plt <- function(dat){
    p <- ggplot(dat, aes(mpg,disp)) + 
      geom_point()

    return(p)
}

p0 <- plt(am0)
p1 <- plt(am1)

# reading image
img <- readPNG(system.file("img", "Rlogo.png", package = "png"))

# adding image
p0 + annotation_custom(rasterGrob(img), xmin = 20, xmax = 25, ymin = 400, ymax = 450)
p1 + annotation_custom(rasterGrob(img), xmin = 30, xmax = 35, ymin = 300, ymax = 350)

leads to the following results: enter image description here

My question is: Is there a way to add images so that the size and the position of the image is constant and not dependent on the scale of the plot? it sould look something like this: enter image description here

like image 884
ehi Avatar asked Oct 18 '22 18:10

ehi


1 Answers

We can automate the process of specifying the location and scales, so that you don't need to change the locations manually, as shown in the following example:

get.xy <- function(p) {
  g_data <- ggplot_build(p)
  data.frame(xmax = max(g_data$data[[1]]$x),
             ymax = max(g_data$data[[1]]$y),
             xmin = min(g_data$data[[1]]$x),
             ymin = min(g_data$data[[1]]$y))
}

# this returns the dataframe with required x, y params for annotation_custom,
# ensuring the size and position of the image constant
get.params.df <- function(p0, p1, width, height) {
  df0 <- cbind.data.frame(get.xy(p0), width=width, height=height)
  df1 <- cbind.data.frame(get.xy(p1))
  df1$width <- df0$width*(df1$xmax-df1$xmin)/(df0$xmax-df0$xmin)
  df1$height <- df0$height*(df1$ymax-df1$ymin)/(df0$ymax-df0$ymin)
  df <- rbind(df0, df1)
  return(data.frame(xmin=df$xmax-df$width, xmax=df$xmax+df$width, ymin=df$ymax-df$height, ymax=df$ymax+df$height))
}

p0 <- plt(am0)
p1 <- plt(am1)

df <- get.params.df(p0, p1, width=10, height=10)

# adding image
library(gridExtra)
grid.arrange(
  p0 + annotation_custom(rasterGrob(img), xmin=df[1,1],xmax=df[1,2], ymin=df[1,3], ymax=df[1,4]),
  p1 + annotation_custom(rasterGrob(img), xmin=df[2,1],xmax=df[2,2], ymin=df[2,3], ymax=df[2,4])  
)

enter image description here

If you want bigger image change the width height parameter only, everything else remains unchanged.

df <- get.params.df(p0, p1, width=25, height=25)
library(gridExtra)
grid.arrange(
  p0 + annotation_custom(rasterGrob(img), xmin=df[1,1],xmax=df[1,2], ymin=df[1,3], ymax=df[1,4]),
  p1 + annotation_custom(rasterGrob(img), xmin=df[2,1],xmax=df[2,2], ymin=df[2,3], ymax=df[2,4])  
)

enter image description here

like image 89
Sandipan Dey Avatar answered Oct 20 '22 11:10

Sandipan Dey