rggplot2ggimage

How to use images as xy-plot points having data driven angles


I can not figure out how to use .gif figures as points in x-y plotting, and rotate each point according to data in the dataset.

Demo dataset:

library("ggplot2")
library("ggimage")
N=5
d <- data.frame(x = rnorm(N),
            y = rnorm(N),
            image = rep("https://www.r-project.org/logo/Rlogo.png", N),
            size = seq(.05, 0.15, length.out = N),
            angle = seq(0, 45, length.out = N) )

The follwing will make a plot where all Rlogo's are rotated 45 degrees:

ggplot(d, aes(x, y)) + 
  geom_image(aes(image=image, size=I(size)), angle = 45)
# Plot with tilted png

But how to set the rotation angle individually for each point? The snippet below simply does not work and makes a plot without tilting any points..

ggplot(d, aes(x, y)) + 
  geom_image(aes(image=image, size=I(size), angle = I(angle)))
#plotting but without tilting the points

Setting the plot angle outside the aes does not help.

ggplot(d, aes(x, y)) + geom_image(aes(image=image, size=I(size)), angle = I(d$angle))
# No plotting: Error in valid.viewport(x, y, width, height, just, gp, clip, xscale, yscale, invalid 'angle' in viewport

So, anyone having a good idea for this? Thanks in advance:-)


Solution

  • You could try this, although the real solution would be to write a better geom,

    library("ggplot2")
    library("egg")
    library("grid")
    N=5
    d <- data.frame(x = rnorm(N),
                    y = rnorm(N),
                    image = replicate(N, system.file("img", "Rlogo.png", package="png")),
                    size = seq(.05, 0.15, length.out = N),
                    angle = seq(0, 45, length.out = N),
                    stringsAsFactors = FALSE)
    
    grobs <- purrr::map2(d$image, runif(N,0,180),
                         function(i,a) list(raster = png::readPNG(i), angle=a) )
    d$grob <- I(grobs)
    
    custom_grob <- function(data, x=0.5, y=0.5){
      grob(data=data$raster,angle=data$angle,x=x,y=y, cl="custom")
    }
    preDrawDetails.custom <- function(x){
      pushViewport(viewport(x=x$x,y=x$y, angle = x$angle))
    }
    postDrawDetails.custom <- function(x){
      upViewport()
    }
    drawDetails.custom <- function(x, recording=FALSE, ...){
      grid.raster(x$data, interpolate = FALSE, width=unit(1,"cm"), height=unit(1,"cm"))
    }
    ggplot(d, aes(x, y)) +
      theme_bw() +
      geom_custom(data = d, aes(data = grob), 
                  grob_fun = custom_grob)
    

    enter image description here